##// 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
@@ -1,94 +1,94
1 if (release != 'rtm') {
1 if (release != 'rtm') {
2 version += "-$release"
2 version += "-$release"
3 }
3 }
4
4
5 println "version: $version"
5 println "version: $version"
6
6
7 def distDir = "$buildDir/dist"
7 def distDir = "$buildDir/dist"
8 def testDir = "$buildDir/test"
8 def testDir = "$buildDir/test"
9
9
10 task clean {
10 task clean {
11 doLast {
11 doLast {
12 delete buildDir
12 delete buildDir
13 delete 'node_modules/@implab'
13 delete 'node_modules/@implab'
14 }
14 }
15 }
15 }
16
16
17 task cleanNpm {
17 task cleanNpm {
18 doLast {
18 doLast {
19 delete 'node_modules'
19 delete 'node_modules'
20 }
20 }
21 }
21 }
22
22
23 task _npmInstall() {
23 task _npmInstall() {
24 inputs.file("package.json")
24 inputs.file("package.json")
25 outputs.dir("node_modules")
25 outputs.dir("node_modules")
26 doLast {
26 doLast {
27 exec {
27 exec {
28 commandLine 'npm', 'install'
28 commandLine 'npm', 'install'
29 }
29 }
30 }
30 }
31 }
31 }
32
32
33 task _legacyJs(type:Copy) {
33 task _legacyJs(type:Copy) {
34 from 'src/js/'
34 from 'src/js/'
35 into distDir
35 into distDir
36 }
36 }
37
37
38 task _buildTs(dependsOn: _npmInstall, type:Exec) {
38 task _buildTs(dependsOn: _npmInstall, type:Exec) {
39 inputs.dir('src/ts')
39 inputs.dir('src/ts')
40 inputs.file('tsc.json')
40 inputs.file('tsc.json')
41 outputs.dir(distDir)
41 outputs.dir(distDir)
42
42
43 commandLine 'node_modules/.bin/tsc', '-p', 'tsconfig.json'
43 commandLine 'node_modules/.bin/tsc', '-p', 'tsconfig.json'
44 }
44 }
45
45
46 task _packageMeta(type: Copy) {
46 task _packageMeta(type: Copy) {
47 inputs.property("version", version)
47 inputs.property("version", version)
48 from('.') {
48 from('.') {
49 include 'package.json', '.npmignore', 'readme.md', 'license', 'history.md'
49 include 'package.json', '.npmignore', 'readme.md', 'license', 'history.md'
50 }
50 }
51 into distDir
51 into distDir
52 doLast {
52 doLast {
53 exec {
53 exec {
54 workingDir distDir
54 workingDir distDir
55 commandLine 'npm', 'version', version
55 commandLine 'npm', 'version', version
56 }
56 }
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
64 task _localInstall(dependsOn: build, type: Exec) {
64 task _localInstall(dependsOn: build, type: Exec) {
65 inputs.file("$distDir/package.json")
65 inputs.file("$distDir/package.json")
66 outputs.upToDateWhen {
66 outputs.upToDateWhen {
67 new File("$projectDir/node_modules/@implab/core").exists()
67 new File("$projectDir/node_modules/@implab/core").exists()
68 }
68 }
69
69
70 commandLine 'npm', 'install', '--no-save', '--force', distDir
70 commandLine 'npm', 'install', '--no-save', '--force', distDir
71 }
71 }
72
72
73 task copyJsTests(type: Copy) {
73 task copyJsTests(type: Copy) {
74 from 'test/js'
74 from 'test/js'
75 into testDir
75 into testDir
76 }
76 }
77
77
78 task buildTests(dependsOn: _localInstall, type: Exec) {
78 task buildTests(dependsOn: _localInstall, type: Exec) {
79 inputs.dir('test/ts')
79 inputs.dir('test/ts')
80 inputs.file('tsc.test.json')
80 inputs.file('tsc.test.json')
81 outputs.dir(testDir)
81 outputs.dir(testDir)
82
82
83 commandLine 'node_modules/.bin/tsc', '-p', 'tsconfig.test.json'
83 commandLine 'node_modules/.bin/tsc', '-p', 'tsconfig.test.json'
84 }
84 }
85
85
86 task test(dependsOn: [copyJsTests, buildTests], type: Exec) {
86 task test(dependsOn: [copyJsTests, buildTests], type: Exec) {
87 commandLine 'node', 'run-amd-tests.js'
87 commandLine 'node', 'run-amd-tests.js'
88 }
88 }
89
89
90 task pack(dependsOn: build, type: Exec) {
90 task pack(dependsOn: build, type: Exec) {
91 workingDir = distDir
91 workingDir = distDir
92
92
93 commandLine 'npm', 'pack'
93 commandLine 'npm', 'pack'
94 } No newline at end of file
94 }
@@ -1,270 +1,270
1 // Typescript port of the uuid.js
1 // Typescript port of the uuid.js
2 // Copyright (c) 2018 Sergey Smirnov
2 // Copyright (c) 2018 Sergey Smirnov
3 // BSD-2-Clause License https://opensource.org/licenses/BSD-2-Clause
3 // BSD-2-Clause License https://opensource.org/licenses/BSD-2-Clause
4 //
4 //
5 // uuid.js
5 // uuid.js
6 // Copyright (c) 2010-2012 Robert Kieffer
6 // Copyright (c) 2010-2012 Robert Kieffer
7 // MIT License - http://opensource.org/licenses/mit-license.php
7 // MIT License - http://opensource.org/licenses/mit-license.php
8
8
9 declare var window: any;
9 declare var window: any;
10
10
11 let _window: any = 'undefined' !== typeof window ? window : null;
11 let _window: any = 'undefined' !== typeof window ? window : null;
12
12
13 // Unique ID creation requires a high quality random # generator. We
13 // Unique ID creation requires a high quality random # generator. We
14 // feature
14 // feature
15 // detect to determine the best RNG source, normalizing to a function
15 // detect to determine the best RNG source, normalizing to a function
16 // that
16 // that
17 // returns 128-bits of randomness, since that's what's usually required
17 // returns 128-bits of randomness, since that's what's usually required
18 let _rng;
18 let _rng;
19
19
20 function setupBrowser() {
20 function setupBrowser() {
21 // Allow for MSIE11 msCrypto
21 // Allow for MSIE11 msCrypto
22 let _crypto = _window.crypto || _window.msCrypto;
22 let _crypto = _window.crypto || _window.msCrypto;
23
23
24 if (!_rng && _crypto && _crypto.getRandomValues) {
24 if (!_rng && _crypto && _crypto.getRandomValues) {
25 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
25 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
26 //
26 //
27 // Moderately fast, high quality
27 // Moderately fast, high quality
28 try {
28 try {
29 let _rnds8 = new Uint8Array(16);
29 let _rnds8 = new Uint8Array(16);
30 _rng = function whatwgRNG() {
30 _rng = function whatwgRNG() {
31 _crypto.getRandomValues(_rnds8);
31 _crypto.getRandomValues(_rnds8);
32 return _rnds8;
32 return _rnds8;
33 };
33 };
34 _rng();
34 _rng();
35 } catch (e) { /**/ }
35 } catch (e) { /**/ }
36 }
36 }
37
37
38 if (!_rng) {
38 if (!_rng) {
39 // Math.random()-based (RNG)
39 // Math.random()-based (RNG)
40 //
40 //
41 // If all else fails, use Math.random(). It's fast, but is of
41 // If all else fails, use Math.random(). It's fast, but is of
42 // unspecified
42 // unspecified
43 // quality.
43 // quality.
44 let _rnds = new Array(16);
44 let _rnds = new Array(16);
45 _rng = function () {
45 _rng = function () {
46 for (var i = 0, r; i < 16; i++) {
46 for (var i = 0, r; i < 16; i++) {
47 if ((i & 0x03) === 0) {
47 if ((i & 0x03) === 0) {
48 r = Math.random() * 0x100000000;
48 r = Math.random() * 0x100000000;
49 }
49 }
50 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
50 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
51 }
51 }
52
52
53 return _rnds;
53 return _rnds;
54 };
54 };
55 if ('undefined' !== typeof console && console.warn) {
55 if ('undefined' !== typeof console && console.warn) {
56 console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
56 console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
57 }
57 }
58 }
58 }
59 }
59 }
60
60
61 function setupNode() {
61 function setupNode() {
62 // Node.js crypto-based RNG -
62 // Node.js crypto-based RNG -
63 // http://nodejs.org/docs/v0.6.2/api/crypto.html
63 // http://nodejs.org/docs/v0.6.2/api/crypto.html
64 //
64 //
65 // Moderately fast, high quality
65 // Moderately fast, high quality
66 if ('function' === typeof require) {
66 if ('function' === typeof require) {
67 try {
67 try {
68 let _rb = require('crypto').randomBytes;
68 let _rb = require('crypto').randomBytes;
69 _rng = _rb && function () {
69 _rng = _rb && function () {
70 return _rb(16);
70 return _rb(16);
71 };
71 };
72 _rng();
72 _rng();
73 } catch (e) { /**/ }
73 } catch (e) { /**/ }
74 }
74 }
75 }
75 }
76
76
77 if (_window) {
77 if (_window) {
78 setupBrowser();
78 setupBrowser();
79 } else {
79 } else {
80 setupNode();
80 setupNode();
81 }
81 }
82
82
83 // Buffer class to use
83 // Buffer class to use
84 let BufferClass = ('function' === typeof Buffer) ? Buffer : Array;
84 let BufferClass = ('function' === typeof Buffer) ? Buffer : Array;
85
85
86 // Maps for number <-> hex string conversion
86 // Maps for number <-> hex string conversion
87 let _byteToHex = [];
87 let _byteToHex = [];
88 let _hexToByte = {};
88 let _hexToByte = {};
89 for (let i = 0; i < 256; i++) {
89 for (let i = 0; i < 256; i++) {
90 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
90 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
91 _hexToByte[_byteToHex[i]] = i;
91 _hexToByte[_byteToHex[i]] = i;
92 }
92 }
93
93
94 // **`parse()` - Parse a UUID into it's component bytes**
94 // **`parse()` - Parse a UUID into it's component bytes**
95 function _parse(s, buf?, offset?): Array<string> {
95 function _parse(s, buf?, offset?): Array<string> {
96 let i = (buf && offset) || 0, ii = 0;
96 let i = (buf && offset) || 0, ii = 0;
97
97
98 buf = buf || [];
98 buf = buf || [];
99 s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) {
99 s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) {
100 if (ii < 16) { // Don't overflow!
100 if (ii < 16) { // Don't overflow!
101 buf[i + ii++] = _hexToByte[oct];
101 buf[i + ii++] = _hexToByte[oct];
102 }
102 }
103 });
103 });
104
104
105 // Zero out remaining bytes if string was short
105 // Zero out remaining bytes if string was short
106 while (ii < 16) {
106 while (ii < 16) {
107 buf[i + ii++] = 0;
107 buf[i + ii++] = 0;
108 }
108 }
109
109
110 return buf;
110 return buf;
111 }
111 }
112
112
113 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
113 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
114 function _unparse(buf, offset?): string {
114 function _unparse(buf, offset?): string {
115 let i = offset || 0, bth = _byteToHex;
115 let i = offset || 0, bth = _byteToHex;
116 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] +
116 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] +
117 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' +
117 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' +
118 bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] +
118 bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] +
119 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] +
119 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] +
120 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
120 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
121 }
121 }
122
122
123 // **`v1()` - Generate time-based UUID**
123 // **`v1()` - Generate time-based UUID**
124 //
124 //
125 // Inspired by https://github.com/LiosK/UUID.js
125 // Inspired by https://github.com/LiosK/UUID.js
126 // and http://docs.python.org/library/uuid.html
126 // and http://docs.python.org/library/uuid.html
127
127
128 // random #'s we need to init node and clockseq
128 // random #'s we need to init node and clockseq
129 let _seedBytes = _rng();
129 let _seedBytes = _rng();
130
130
131 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit =
131 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit =
132 // 1)
132 // 1)
133 let _nodeId = [
133 let _nodeId = [
134 _seedBytes[0] | 0x01,
134 _seedBytes[0] | 0x01,
135 _seedBytes[1],
135 _seedBytes[1],
136 _seedBytes[2],
136 _seedBytes[2],
137 _seedBytes[3],
137 _seedBytes[3],
138 _seedBytes[4],
138 _seedBytes[4],
139 _seedBytes[5]
139 _seedBytes[5]
140 ];
140 ];
141
141
142 // Per 4.2.2, randomize (14 bit) clockseq
142 // Per 4.2.2, randomize (14 bit) clockseq
143 let _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
143 let _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
144
144
145 // Previous uuid creation time
145 // Previous uuid creation time
146 let _lastMSecs = 0, _lastNSecs = 0;
146 let _lastMSecs = 0, _lastNSecs = 0;
147
147
148 // See https://github.com/broofa/node-uuid for API details
148 // See https://github.com/broofa/node-uuid for API details
149 function _v1(options?, buf?, offset?): string {
149 function _v1(options?, buf?, offset?): string {
150 let i = buf && offset || 0;
150 let i = buf && offset || 0;
151 let b = buf || [];
151 let b = buf || [];
152
152
153 options = options || {};
153 options = options || {};
154
154
155 let clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
155 let clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
156
156
157 // UUID timestamps are 100 nano-second units since the Gregorian
157 // UUID timestamps are 100 nano-second units since the Gregorian
158 // epoch,
158 // epoch,
159 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
159 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
160 // time is handled internally as 'msecs' (integer milliseconds) and
160 // time is handled internally as 'msecs' (integer milliseconds) and
161 // 'nsecs'
161 // 'nsecs'
162 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01
162 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01
163 // 00:00.
163 // 00:00.
164 let msecs = (options.msecs != null) ? options.msecs : new Date()
164 let msecs = (options.msecs != null) ? options.msecs : new Date()
165 .getTime();
165 .getTime();
166
166
167 // Per 4.2.1.2, use count of uuid's generated during the current
167 // Per 4.2.1.2, use count of uuid's generated during the current
168 // clock
168 // clock
169 // cycle to simulate higher resolution clock
169 // cycle to simulate higher resolution clock
170 let nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
170 let nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
171
171
172 // Time since last uuid creation (in msecs)
172 // Time since last uuid creation (in msecs)
173 let dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
173 let dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
174
174
175 // Per 4.2.1.2, Bump clockseq on clock regression
175 // Per 4.2.1.2, Bump clockseq on clock regression
176 if (dt < 0 && options.clockseq == null) {
176 if (dt < 0 && options.clockseq == null) {
177 clockseq = clockseq + 1 & 0x3fff;
177 clockseq = clockseq + 1 & 0x3fff;
178 }
178 }
179
179
180 // Reset nsecs if clock regresses (new clockseq) or we've moved onto
180 // Reset nsecs if clock regresses (new clockseq) or we've moved onto
181 // a new
181 // a new
182 // time interval
182 // time interval
183 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
183 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
184 nsecs = 0;
184 nsecs = 0;
185 }
185 }
186
186
187 // Per 4.2.1.2 Throw error if too many uuids are requested
187 // Per 4.2.1.2 Throw error if too many uuids are requested
188 if (nsecs >= 10000) {
188 if (nsecs >= 10000) {
189 throw new Error(
189 throw new Error(
190 'uuid.v1(): Can\'t create more than 10M uuids/sec');
190 'uuid.v1(): Can\'t create more than 10M uuids/sec');
191 }
191 }
192
192
193 _lastMSecs = msecs;
193 _lastMSecs = msecs;
194 _lastNSecs = nsecs;
194 _lastNSecs = nsecs;
195 _clockseq = clockseq;
195 _clockseq = clockseq;
196
196
197 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
197 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
198 msecs += 12219292800000;
198 msecs += 12219292800000;
199
199
200 // `time_low`
200 // `time_low`
201 let tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
201 let tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
202 b[i++] = tl >>> 24 & 0xff;
202 b[i++] = tl >>> 24 & 0xff;
203 b[i++] = tl >>> 16 & 0xff;
203 b[i++] = tl >>> 16 & 0xff;
204 b[i++] = tl >>> 8 & 0xff;
204 b[i++] = tl >>> 8 & 0xff;
205 b[i++] = tl & 0xff;
205 b[i++] = tl & 0xff;
206
206
207 // `time_mid`
207 // `time_mid`
208 let tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
208 let tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
209 b[i++] = tmh >>> 8 & 0xff;
209 b[i++] = tmh >>> 8 & 0xff;
210 b[i++] = tmh & 0xff;
210 b[i++] = tmh & 0xff;
211
211
212 // `time_high_and_version`
212 // `time_high_and_version`
213 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
213 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
214 b[i++] = tmh >>> 16 & 0xff;
214 b[i++] = tmh >>> 16 & 0xff;
215
215
216 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
216 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
217 b[i++] = clockseq >>> 8 | 0x80;
217 b[i++] = clockseq >>> 8 | 0x80;
218
218
219 // `clock_seq_low`
219 // `clock_seq_low`
220 b[i++] = clockseq & 0xff;
220 b[i++] = clockseq & 0xff;
221
221
222 // `node`
222 // `node`
223 let node = options.node || _nodeId;
223 let node = options.node || _nodeId;
224 for (let n = 0; n < 6; n++) {
224 for (let n = 0; n < 6; n++) {
225 b[i + n] = node[n];
225 b[i + n] = node[n];
226 }
226 }
227
227
228 return buf ? buf : _unparse(b);
228 return buf ? buf : _unparse(b);
229 }
229 }
230
230
231 // **`v4()` - Generate random UUID**
231 // **`v4()` - Generate random UUID**
232
232
233 // See https://github.com/broofa/node-uuid for API details
233 // See https://github.com/broofa/node-uuid for API details
234 function _v4(options?, buf?, offset?): string {
234 function _v4(options?, buf?, offset?): string {
235 // Deprecated - 'format' argument, as supported in v1.2
235 // Deprecated - 'format' argument, as supported in v1.2
236 let i = buf && offset || 0;
236 let i = buf && offset || 0;
237
237
238 if (typeof (options) === 'string') {
238 if (typeof (options) === 'string') {
239 buf = (options === 'binary') ? new BufferClass(16) : null;
239 buf = (options === 'binary') ? new BufferClass(16) : null;
240 options = null;
240 options = null;
241 }
241 }
242 options = options || {};
242 options = options || {};
243
243
244 let rnds = options.random || (options.rng || _rng)();
244 let rnds = options.random || (options.rng || _rng)();
245
245
246 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
246 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
247 rnds[6] = (rnds[6] & 0x0f) | 0x40;
247 rnds[6] = (rnds[6] & 0x0f) | 0x40;
248 rnds[8] = (rnds[8] & 0x3f) | 0x80;
248 rnds[8] = (rnds[8] & 0x3f) | 0x80;
249
249
250 // Copy bytes to buffer, if provided
250 // Copy bytes to buffer, if provided
251 if (buf) {
251 if (buf) {
252 for (let ii = 0; ii < 16; ii++) {
252 for (let ii = 0; ii < 16; ii++) {
253 buf[i + ii] = rnds[ii];
253 buf[i + ii] = rnds[ii];
254 }
254 }
255 }
255 }
256
256
257 return buf || _unparse(rnds);
257 return buf || _unparse(rnds);
258 }
258 }
259
259
260 export function Uuid() {
260 export function Uuid() {
261
261 return _v4();
262 }
262 }
263
263
264 export namespace Uuid {
264 export namespace Uuid {
265 export const v4 = _v4;
265 export const v4 = _v4;
266 export const v1 = _v1;
266 export const v1 = _v1;
267 export const empty = "00000000-0000-0000-0000-000000000000";
267 export const empty = "00000000-0000-0000-0000-000000000000";
268 export const parse = _parse;
268 export const parse = _parse;
269 export const unparse = _unparse;
269 export const unparse = _unparse;
270 } No newline at end of file
270 }
@@ -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,132 +1,140
1 import { TraceSource } from "../log/TraceSource";
1 import { TraceSource } from "../log/TraceSource";
2 import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "../safe";
2 import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "../safe";
3 import { Uuid } from '../Uuid';
3 import { Descriptor, ServiceMap, isDescriptor } from "./interfaces";
4 import { Container, ActivationContextInfo, ServiceMap, Descriptor, isDescriptor } from "../di";
4 import { Container } from "./Container";
5
5
6 let trace = TraceSource.get("di");
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 export class ActivationContext {
17 export class ActivationContext {
10 _cache: object
18 _cache: object
11
19
12 _services: ServiceMap
20 _services: ServiceMap
13
21
14 _stack: ActivationContextInfo[]
22 _stack: ActivationContextInfo[]
15
23
16 _visited: any
24 _visited: any
17
25
18 container: any
26 container: any
19
27
20
28
21 constructor(container: Container, services: ServiceMap, cache?: object, visited?) {
29 constructor(container: Container, services: ServiceMap, cache?: object, visited?) {
22 argumentNotNull(container, "container");
30 argumentNotNull(container, "container");
23 argumentNotNull(services, "services");
31 argumentNotNull(services, "services");
24
32
25 this._visited = visited || {};
33 this._visited = visited || {};
26 this._stack = [];
34 this._stack = [];
27 this._cache = cache || {};
35 this._cache = cache || {};
28 this._services = services;
36 this._services = services;
29 this.container = container;
37 this.container = container;
30 }
38 }
31
39
32 getService(name, def?): any {
40 getService(name, def?): any {
33 let d = this._services[name];
41 let d = this._services[name];
34
42
35 if (!d)
43 if (!d)
36 if (arguments.length > 1)
44 if (arguments.length > 1)
37 return def;
45 return def;
38 else
46 else
39 throw new Error("Service '" + name + "' not found");
47 throw new Error("Service '" + name + "' not found");
40
48
41 return d.activate(this, name);
49 return d.activate(this, name);
42 }
50 }
43
51
44 /**
52 /**
45 * registers services local to the the activation context
53 * registers services local to the the activation context
46 *
54 *
47 * @name{string} the name of the service
55 * @name{string} the name of the service
48 * @service{string} the service descriptor to register
56 * @service{string} the service descriptor to register
49 */
57 */
50 register(name: string, service: Descriptor) {
58 register(name: string, service: Descriptor) {
51 argumentNotEmptyString(name, "name");
59 argumentNotEmptyString(name, "name");
52
60
53 this._services[name] = service;
61 this._services[name] = service;
54 }
62 }
55
63
56 clone() {
64 clone() {
57 return new ActivationContext(
65 return new ActivationContext(
58 this.container,
66 this.container,
59 Object.create(this._services),
67 Object.create(this._services),
60 this._cache,
68 this._cache,
61 this._visited
69 this._visited
62 );
70 );
63
71
64 }
72 }
65
73
66 has(id) {
74 has(id) {
67 return id in this._cache;
75 return id in this._cache;
68 }
76 }
69
77
70 get(id) {
78 get(id) {
71 return this._cache[id];
79 return this._cache[id];
72 }
80 }
73
81
74 store(id, value) {
82 store(id, value) {
75 return (this._cache[id] = value);
83 return (this._cache[id] = value);
76 }
84 }
77
85
78 parse(data: any, name) {
86 parse(data: any, name) {
79 var me = this;
87 var me = this;
80 if (isPrimitive(data))
88 if (isPrimitive(data))
81 return data;
89 return data;
82
90
83 if (isDescriptor(data)) {
91 if (isDescriptor(data)) {
84 return data.activate(this, name);
92 return data.activate(this, name);
85 } else if (data instanceof Array) {
93 } else if (data instanceof Array) {
86 me.enter(name);
94 me.enter(name);
87 var v = data.map(function (x, i) {
95 var v = data.map(function (x, i) {
88 return me.parse(x, "." + i);
96 return me.parse(x, "." + i);
89 });
97 });
90 me.leave();
98 me.leave();
91 return v;
99 return v;
92 } else {
100 } else {
93 me.enter(name);
101 me.enter(name);
94 var result = {};
102 var result = {};
95 for (var p in data)
103 for (var p in data)
96 result[p] = me.parse(data[p], "." + p);
104 result[p] = me.parse(data[p], "." + p);
97 me.leave();
105 me.leave();
98 return result;
106 return result;
99 }
107 }
100 }
108 }
101
109
102 visit(id) {
110 visit(id) {
103 var count = this._visited[id] || 0;
111 var count = this._visited[id] || 0;
104 this._visited[id] = count + 1;
112 this._visited[id] = count + 1;
105 return count;
113 return count;
106 }
114 }
107
115
108 getStack() {
116 getStack() {
109 return this._stack.slice().reverse();
117 return this._stack.slice().reverse();
110 }
118 }
111
119
112 enter(name, d?, localize?) {
120 enter(name, d?, localize?) {
113 if (trace.isLogEnabled())
121 if (trace.isLogEnabled())
114 trace.log("enter " + name + " " + (d || "") +
122 trace.log("enter " + name + " " + (d || "") +
115 (localize ? " localize" : ""));
123 (localize ? " localize" : ""));
116 this._stack.push({
124 this._stack.push({
117 name: name,
125 name: name,
118 service: d,
126 service: d,
119 scope: this._services
127 scope: this._services
120 });
128 });
121 if (localize)
129 if (localize)
122 this._services = Object.create(this._services);
130 this._services = Object.create(this._services);
123 }
131 }
124
132
125 leave() {
133 leave() {
126 var ctx = this._stack.pop();
134 var ctx = this._stack.pop();
127 this._services = ctx.scope;
135 this._services = ctx.scope;
128
136
129 if (trace.isLogEnabled())
137 if (trace.isLogEnabled())
130 trace.log("leave " + ctx.name + " " + (ctx.service || ""));
138 trace.log("leave " + ctx.name + " " + (ctx.service || ""));
131 }
139 }
132 } No newline at end of file
140 }
@@ -1,282 +1,292
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 import { Uuid } from "../Uuid";
5 import { Uuid } from "../Uuid";
2 import { ActivationContext } from "./ActivationContext";
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 export class Container {
16 export class Container {
7 _services
17 _services
8
18
9 _cache
19 _cache
10
20
11 _cleanup: any[]
21 _cleanup: any[]
12
22
13 _root: Container
23 _root: Container
14
24
15 _parent: Container
25 _parent: Container
16
26
17 constructor(parent?: Container) {
27 constructor(parent?: Container) {
18 this._parent = parent;
28 this._parent = parent;
19 this._services = parent ? Object.create(parent._services) : {};
29 this._services = parent ? Object.create(parent._services) : {};
20 this._cache = {};
30 this._cache = {};
21 this._cleanup = [];
31 this._cleanup = [];
22 this._root = parent ? parent.getRootContainer() : this;
32 this._root = parent ? parent.getRootContainer() : this;
23 this._services.container = new ValueDescriptor(this);
33 this._services.container = new ValueDescriptor(this);
24 }
34 }
25
35
26 getRootContainer() {
36 getRootContainer() {
27 return this._root;
37 return this._root;
28 }
38 }
29
39
30 getParent() {
40 getParent() {
31 return this._parent;
41 return this._parent;
32 }
42 }
33
43
34 getService<T = any>(name: string, def?: T) {
44 getService<T = any>(name: string, def?: T) {
35 let d = this._services[name];
45 let d = this._services[name];
36 if (!d)
46 if (!d)
37 if (arguments.length > 1)
47 if (arguments.length > 1)
38 return def;
48 return def;
39 else
49 else
40 throw new Error("Service '" + name + "' isn't found");
50 throw new Error("Service '" + name + "' isn't found");
41
51
42 if (d.isInstanceCreated())
52 if (d.isInstanceCreated())
43 return d.getInstance();
53 return d.getInstance();
44
54
45 var context = new ActivationContext(this, this._services);
55 var context = new ActivationContext(this, this._services);
46
56
47 try {
57 try {
48 return d.activate(context, name);
58 return d.activate(context, name);
49 } catch (error) {
59 } catch (error) {
50 throw new ActivationError(name, context.getStack(), error);
60 throw new ActivationError(name, context.getStack(), error);
51 }
61 }
52 }
62 }
53
63
54 register(nameOrCollection, service?) {
64 register(nameOrCollection, service?) {
55 if (arguments.length == 1) {
65 if (arguments.length == 1) {
56 var data = nameOrCollection;
66 var data = nameOrCollection;
57 for (let name in data)
67 for (let name in data)
58 this.register(name, data[name]);
68 this.register(name, data[name]);
59 } else {
69 } else {
60 if (!(service instanceof Descriptor))
70 if (!(isDescriptor(service)))
61 service = new ValueDescriptor(service);
71 service = new ValueDescriptor(service);
62 this._services[nameOrCollection] = service;
72 this._services[nameOrCollection] = service;
63 }
73 }
64 return this;
74 return this;
65 }
75 }
66
76
67 onDispose(callback) {
77 onDispose(callback) {
68 if (!(callback instanceof Function))
78 if (!(callback instanceof Function))
69 throw new Error("The callback must be a function");
79 throw new Error("The callback must be a function");
70 this._cleanup.push(callback);
80 this._cleanup.push(callback);
71 }
81 }
72
82
73 dispose() {
83 dispose() {
74 if (this._cleanup) {
84 if (this._cleanup) {
75 for (var i = 0; i < this._cleanup.length; i++)
85 for (var i = 0; i < this._cleanup.length; i++)
76 this._cleanup[i].call(null);
86 this._cleanup[i].call(null);
77 this._cleanup = null;
87 this._cleanup = null;
78 }
88 }
79 }
89 }
80
90
81 /**
91 /**
82 * @param{String|Object} config
92 * @param{String|Object} config
83 * The configuration of the contaier. Can be either a string or an object,
93 * The configuration of the contaier. Can be either a string or an object,
84 * if the configuration is an object it's treated as a collection of
94 * if the configuration is an object it's treated as a collection of
85 * services which will be registed in the contaier.
95 * services which will be registed in the contaier.
86 *
96 *
87 * @param{Function} opts.contextRequire
97 * @param{Function} opts.contextRequire
88 * The function which will be used to load a configuration or types for services.
98 * The function which will be used to load a configuration or types for services.
89 *
99 *
90 */
100 */
91 async configure(config, opts) {
101 async configure(config, opts) {
92 var me = this,
102 var me = this,
93 contextRequire = (opts && opts.contextRequire);
103 contextRequire = (opts && opts.contextRequire);
94
104
95 if (typeof (config) === "string") {
105 if (typeof (config) === "string") {
96 let args;
106 let args;
97 if (!contextRequire) {
107 if (!contextRequire) {
98 var shim = [config, Uuid()].join(config.indexOf("/") != -1 ? "-" : "/");
108 var shim = [config, Uuid()].join(config.indexOf("/") != -1 ? "-" : "/");
99 args = await new Promise((resolve, reject) => {
109 args = await new Promise((resolve, reject) => {
100 define(shim, ["require", config], function (ctx, data) {
110 define(shim, ["require", config], function (ctx, data) {
101 resolve([data, {
111 resolve([data, {
102 contextRequire: ctx
112 contextRequire: ctx
103 }]);
113 }]);
104 })
114 })
105 });
115 });
106 require([shim]);
116 require([shim]);
107 } else {
117 } else {
108 // TODO how to get correct contextRequire for the relative config module?
118 // TODO how to get correct contextRequire for the relative config module?
109 args = await new Promise((resolve, reject) => {
119 args = await new Promise((resolve, reject) => {
110 contextRequire([config], function (data) {
120 contextRequire([config], function (data) {
111 resolve([data, {
121 resolve([data, {
112 contextRequire: contextRequire
122 contextRequire: contextRequire
113 }]);
123 }]);
114 });
124 });
115 });
125 });
116 }
126 }
117
127
118 return me._configure.apply(me, args);
128 return me._configure.apply(me, args);
119 } else {
129 } else {
120 return me._configure(config, opts);
130 return me._configure(config, opts);
121 }
131 }
122 }
132 }
123
133
124 createChildContainer() {
134 createChildContainer() {
125 return new Container(this);
135 return new Container(this);
126 }
136 }
127
137
128 has(id) {
138 has(id) {
129 return id in this._cache;
139 return id in this._cache;
130 }
140 }
131
141
132 get(id) {
142 get(id) {
133 return this._cache[id];
143 return this._cache[id];
134 }
144 }
135
145
136 store(id, value) {
146 store(id, value) {
137 return (this._cache[id] = value);
147 return (this._cache[id] = value);
138 }
148 }
139
149
140 async _configure(data, opts) {
150 async _configure(data, opts) {
141 var typemap = {},
151 var typemap = {},
142 me = this,
152 me = this,
143 p,
153 p,
144 contextRequire = (opts && opts.contextRequire) || require;
154 contextRequire = (opts && opts.contextRequire) || require;
145
155
146 var services = {};
156 var services = {};
147
157
148 for (p in data) {
158 for (p in data) {
149 var service = me._parse(data[p], typemap);
159 var service = me._parse(data[p], typemap);
150 if (!(service instanceof Descriptor))
160 if (!(isDescriptor(service)))
151 service = new AggregateDescriptor(service);
161 service = new AggregateDescriptor(service);
152 services[p] = service;
162 services[p] = service;
153 }
163 }
154
164
155 me.register(services);
165 me.register(services);
156
166
157 var names = [];
167 var names = [];
158
168
159 for (p in typemap)
169 for (p in typemap)
160 names.push(p);
170 names.push(p);
161
171
162 return new Promise((resolve, reject) => {
172 return new Promise((resolve, reject) => {
163 if (names.length) {
173 if (names.length) {
164 contextRequire(names, function () {
174 contextRequire(names, function () {
165 for (var i = 0; i < names.length; i++)
175 for (var i = 0; i < names.length; i++)
166 typemap[names[i]] = arguments[i];
176 typemap[names[i]] = arguments[i];
167 resolve(me);
177 resolve(me);
168 });
178 });
169 } else {
179 } else {
170 resolve(me);
180 resolve(me);
171 }
181 }
172 });
182 });
173
183
174 }
184 }
175
185
176 _parse(data, typemap) {
186 _parse(data, typemap) {
177 if (isPrimitive(data) || data instanceof Descriptor)
187 if (isPrimitive(data) || isDescriptor(data))
178 return data;
188 return data;
179 if (data.$dependency) {
189 if (data.$dependency) {
180 return new ReferenceDescriptor(
190 return new ReferenceDescriptor(
181 data.$dependency,
191 data.$dependency,
182 data.lazy,
192 data.lazy,
183 data.optional,
193 data.optional,
184 data["default"],
194 data["default"],
185 data.services && this._parseObject(data.services, typemap));
195 data.services && this._parseObject(data.services, typemap));
186 } else if (data.$value) {
196 } else if (data.$value) {
187 return !data.parse ?
197 return !data.parse ?
188 new ValueDescriptor(data.$value) :
198 new ValueDescriptor(data.$value) :
189 new AggregateDescriptor(this._parse(data.$value, typemap));
199 new AggregateDescriptor(this._parse(data.$value, typemap));
190 } else if (data.$type || data.$factory) {
200 } else if (data.$type || data.$factory) {
191 return this._parseService(data, typemap);
201 return this._parseService(data, typemap);
192 } else if (data instanceof Array) {
202 } else if (data instanceof Array) {
193 return this._parseArray(data, typemap);
203 return this._parseArray(data, typemap);
194 }
204 }
195
205
196 return this._parseObject(data, typemap);
206 return this._parseObject(data, typemap);
197 }
207 }
198
208
199 _parseService(data, typemap) {
209 _parseService(data, typemap) {
200 var me = this,
210 var me = this,
201 opts: any = {
211 opts: any = {
202 owner: this
212 owner: this
203 };
213 };
204 if (data.$type) {
214 if (data.$type) {
205
215
206 opts.type = data.$type;
216 opts.type = data.$type;
207
217
208 if (typeof (data.$type) === "string") {
218 if (typeof (data.$type) === "string") {
209 typemap[data.$type] = null;
219 typemap[data.$type] = null;
210 opts.typeMap = typemap;
220 opts.typeMap = typemap;
211 }
221 }
212 }
222 }
213
223
214 if (data.$factory)
224 if (data.$factory)
215 opts.factory = data.$factory;
225 opts.factory = data.$factory;
216
226
217 if (data.services)
227 if (data.services)
218 opts.services = me._parseObject(data.services, typemap);
228 opts.services = me._parseObject(data.services, typemap);
219 if (data.inject)
229 if (data.inject)
220 opts.inject = data.inject instanceof Array ? data.inject.map(function (x) {
230 opts.inject = data.inject instanceof Array ? data.inject.map(function (x) {
221 return me._parseObject(x, typemap);
231 return me._parseObject(x, typemap);
222 }) : me._parseObject(data.inject, typemap);
232 }) : me._parseObject(data.inject, typemap);
223 if (data.params)
233 if (data.params)
224 opts.params = me._parse(data.params, typemap);
234 opts.params = me._parse(data.params, typemap);
225
235
226 if (data.activation) {
236 if (data.activation) {
227 if (typeof (data.activation) === "string") {
237 if (typeof (data.activation) === "string") {
228 switch (data.activation.toLowerCase()) {
238 switch (data.activation.toLowerCase()) {
229 case "singleton":
239 case "singleton":
230 opts.activation = ActivationType.SINGLETON;
240 opts.activation = ActivationType.SINGLETON;
231 break;
241 break;
232 case "container":
242 case "container":
233 opts.activation = ActivationType.CONTAINER;
243 opts.activation = ActivationType.CONTAINER;
234 break;
244 break;
235 case "hierarchy":
245 case "hierarchy":
236 opts.activation = ActivationType.HIERARCHY;
246 opts.activation = ActivationType.HIERARCHY;
237 break;
247 break;
238 case "context":
248 case "context":
239 opts.activation = ActivationType.CONTEXT;
249 opts.activation = ActivationType.CONTEXT;
240 break;
250 break;
241 case "call":
251 case "call":
242 opts.activation = ActivationType.CALL;
252 opts.activation = ActivationType.CALL;
243 break;
253 break;
244 default:
254 default:
245 throw new Error("Unknown activation type: " +
255 throw new Error("Unknown activation type: " +
246 data.activation);
256 data.activation);
247 }
257 }
248 } else {
258 } else {
249 opts.activation = Number(data.activation);
259 opts.activation = Number(data.activation);
250 }
260 }
251 }
261 }
252
262
253 if (data.cleanup)
263 if (data.cleanup)
254 opts.cleanup = data.cleanup;
264 opts.cleanup = data.cleanup;
255
265
256 return new ServiceDescriptor(opts);
266 return new ServiceDescriptor(opts);
257 }
267 }
258
268
259 _parseObject(data, typemap) {
269 _parseObject(data, typemap) {
260 if (data.constructor &&
270 if (data.constructor &&
261 data.constructor.prototype !== Object.prototype)
271 data.constructor.prototype !== Object.prototype)
262 return new ValueDescriptor(data);
272 return new ValueDescriptor(data);
263
273
264 var o = {};
274 var o = {};
265
275
266 for (var p in data)
276 for (var p in data)
267 o[p] = this._parse(data[p], typemap);
277 o[p] = this._parse(data[p], typemap);
268
278
269 return o;
279 return o;
270 }
280 }
271
281
272 _parseArray(data, typemap) {
282 _parseArray(data, typemap) {
273 if (data.constructor &&
283 if (data.constructor &&
274 data.constructor.prototype !== Array.prototype)
284 data.constructor.prototype !== Array.prototype)
275 return new ValueDescriptor(data);
285 return new ValueDescriptor(data);
276
286
277 var me = this;
287 var me = this;
278 return data.map(function (x) {
288 return data.map(function (x) {
279 return me._parse(x, typemap);
289 return me._parse(x, typemap);
280 });
290 });
281 }
291 }
282 } No newline at end of file
292 }
@@ -1,98 +1,100
1 import { isNull, argumentNotEmptyString, each } from "../safe";
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 _name: string
7 _name: string
5
8
6 _lazy = false
9 _lazy = false
7
10
8 _optional = false
11 _optional = false
9
12
10 _default: any
13 _default: any
11
14
12 _services: object
15 _services: ServiceMap
13
16
14 constructor(name: string, lazy: boolean, optional: boolean, def, services: object) {
17 constructor(name: string, lazy: boolean, optional: boolean, def, services: ServiceMap) {
15 super();
16 argumentNotEmptyString(name, "name");
18 argumentNotEmptyString(name, "name");
17 this._name = name;
19 this._name = name;
18 this._lazy = Boolean(lazy);
20 this._lazy = Boolean(lazy);
19 this._optional = Boolean(optional);
21 this._optional = Boolean(optional);
20 this._default = def;
22 this._default = def;
21 this._services = services;
23 this._services = services;
22 }
24 }
23
25
24 activate(context: ActivationContext, name: string) {
26 activate(context: ActivationContext, name: string) {
25 var me = this;
27 var me = this;
26
28
27 context.enter(name, this, true);
29 context.enter(name, this, true);
28
30
29 // добавляем сервисы
31 // добавляем сервисы
30 if (me._services) {
32 if (me._services) {
31 for (var p in me._services) {
33 for (var p in me._services) {
32 var sv = me._services[p];
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 if (me._lazy) {
39 if (me._lazy) {
38 // сохраняем контекст активации
40 // сохраняем контекст активации
39 context = context.clone();
41 context = context.clone();
40 return function (cfg) {
42 return function (cfg: ServiceMap) {
41 // защищаем контекст на случай исключения в процессе
43 // защищаем контекст на случай исключения в процессе
42 // активации
44 // активации
43 var ct = context.clone();
45 var ct = context.clone();
44 try {
46 try {
45 if (cfg)
47 if (cfg)
46 each(cfg, function (v, k) {
48 for(let k in cfg)
47 ct.register(k, v instanceof Descriptor ? v : new AggregateDescriptor(v));
49 ct.register(k, cfg[v]);
48 });
50
49 return me._optional ? ct.getService(me._name, me._default) : ct
51 return me._optional ? ct.getService(me._name, me._default) : ct
50 .getService(me._name);
52 .getService(me._name);
51 } catch (error) {
53 } catch (error) {
52 throw new ActivationError(me._name, ct.getStack(), error);
54 throw new ActivationError(me._name, ct.getStack(), error);
53 }
55 }
54 };
56 };
55 }
57 }
56
58
57 var v = me._optional ?
59 var v = me._optional ?
58 context.getService(me._name, me._default) :
60 context.getService(me._name, me._default) :
59 context.getService(me._name);
61 context.getService(me._name);
60
62
61 context.leave();
63 context.leave();
62 return v;
64 return v;
63 }
65 }
64
66
65 isInstanceCreated() {
67 isInstanceCreated() {
66 return false;
68 return false;
67 }
69 }
68
70
69 getInstance() {
71 getInstance() {
70 throw new Error("The reference descriptor doesn't allowed to hold an instance");
72 throw new Error("The reference descriptor doesn't allowed to hold an instance");
71 }
73 }
72
74
73 toString() {
75 toString() {
74 var opts = [];
76 var opts = [];
75 if (this._optional)
77 if (this._optional)
76 opts.push("optional");
78 opts.push("optional");
77 if (this._lazy)
79 if (this._lazy)
78 opts.push("lazy");
80 opts.push("lazy");
79
81
80 var parts = [
82 var parts = [
81 "@ref "
83 "@ref "
82 ];
84 ];
83 if (opts.length) {
85 if (opts.length) {
84 parts.push("{");
86 parts.push("{");
85 parts.push(opts.join());
87 parts.push(opts.join());
86 parts.push("} ");
88 parts.push("} ");
87 }
89 }
88
90
89 parts.push(this._name);
91 parts.push(this._name);
90
92
91 if (!isNull(this._default)) {
93 if (!isNull(this._default)) {
92 parts.push(" = ");
94 parts.push(" = ");
93 parts.push(this._default);
95 parts.push(this._default);
94 }
96 }
95
97
96 return parts.join("");
98 return parts.join("");
97 }
99 }
98 } No newline at end of file
100 }
@@ -1,279 +1,305
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 export function argumentNotNull(arg, name) {
14 export function argumentNotNull(arg, name) {
2 if (arg === null || arg === undefined)
15 if (arg === null || arg === undefined)
3 throw new Error("The argument " + name + " can't be null or undefined");
16 throw new Error("The argument " + name + " can't be null or undefined");
4 }
17 }
5
18
6 export function argumentNotEmptyString(arg, name) {
19 export function argumentNotEmptyString(arg, name) {
7 if (typeof (arg) !== "string" || !arg.length)
20 if (typeof (arg) !== "string" || !arg.length)
8 throw new Error("The argument '" + name + "' must be a not empty string");
21 throw new Error("The argument '" + name + "' must be a not empty string");
9 }
22 }
10
23
11 export function argumentNotEmptyArray(arg, name) {
24 export function argumentNotEmptyArray(arg, name) {
12 if (!(arg instanceof Array) || !arg.length)
25 if (!(arg instanceof Array) || !arg.length)
13 throw new Error("The argument '" + name + "' must be a not empty array");
26 throw new Error("The argument '" + name + "' must be a not empty array");
14 }
27 }
15
28
16 export function argumentOfType(arg, type, name) {
29 export function argumentOfType(arg, type, name) {
17 if (!(arg instanceof type))
30 if (!(arg instanceof type))
18 throw new Error("The argument '" + name + "' type doesn't match");
31 throw new Error("The argument '" + name + "' type doesn't match");
19 }
32 }
20
33
21 export function isNull(arg) {
34 export function isNull(arg) {
22 return (arg === null || arg === undefined);
35 return (arg === null || arg === undefined);
23 }
36 }
24
37
25 export function isPrimitive(arg) {
38 export function isPrimitive(arg) {
26 return (arg === null || arg === undefined || typeof (arg) === "string" ||
39 return (arg === null || arg === undefined || typeof (arg) === "string" ||
27 typeof (arg) === "number" || typeof (arg) === "boolean");
40 typeof (arg) === "number" || typeof (arg) === "boolean");
28 }
41 }
29
42
30 export function isInteger(arg) {
43 export function isInteger(arg) {
31 return parseInt(arg) == arg;
44 return parseInt(arg, 10) === arg;
32 }
45 }
33
46
34 export function isNumber(arg) {
47 export function isNumber(arg) {
35 return parseFloat(arg) == arg;
48 return parseFloat(arg) === arg;
36 }
49 }
37
50
38 export function isString(val) {
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 export function isNullOrEmptyString(str) {
55 export function isNullOrEmptyString(str) {
43 if (str === null || str === undefined ||
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 return true;
58 return true;
46 }
59 }
47
60
48 export function isNotEmptyArray(arg): arg is Array<any> {
61 export function isNotEmptyArray(arg): arg is Array<any> {
49 return (arg instanceof Array && arg.length > 0);
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 * либо достигнут конец массива, либо функция <c>cb</c> вернула
84 * либо достигнут конец массива, либо функция <c>cb</c> вернула
55 * значение.
85 * значение.
56 *
86 *
57 * @param {Array | Object} obj массив элементов для просмотра
87 * @param {Array | Object} obj массив элементов для просмотра
58 * @param {Function} cb функция, вызываемая для каждого элемента
88 * @param {Function} cb функция, вызываемая для каждого элемента
59 * @param {Object} thisArg значение, которое будет передано в качестве
89 * @param {Object} thisArg значение, которое будет передано в качестве
60 * <c>this</c> в <c>cb</c>.
90 * <c>this</c> в <c>cb</c>.
61 * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
91 * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
62 * если достигнут конец массива.
92 * если достигнут конец массива.
63 */
93 */
64 export function each(obj, cb, thisArg?) {
94 export function each(obj, cb, thisArg?) {
65 argumentNotNull(cb, "cb");
95 argumentNotNull(cb, "cb");
66 var i, x;
67 if (obj instanceof Array) {
96 if (obj instanceof Array) {
68 for (i = 0; i < obj.length; i++) {
97 for (let i = 0; i < obj.length; i++) {
69 x = cb.call(thisArg, obj[i], i);
98 const x = cb.call(thisArg, obj[i], i);
70 if (x !== undefined)
99 if (x !== undefined)
71 return x;
100 return x;
72 }
101 }
73 } else {
102 } else {
74 var keys = Object.keys(obj);
103 const keys = Object.keys(obj);
75 for (i = 0; i < keys.length; i++) {
104 for (const k of keys) {
76 var k = keys[i];
105 const x = cb.call(thisArg, obj[k], k);
77 x = cb.call(thisArg, obj[k], k);
78 if (x !== undefined)
106 if (x !== undefined)
79 return x;
107 return x;
80 }
108 }
81 }
109 }
82 }
110 }
83
111
84 /** Copies property values from a source object to the destination and returns
112 /** Copies property values from a source object to the destination and returns
85 * the destination onject.
113 * the destination onject.
86 *
114 *
87 * @param dest The destination object into which properties from the source
115 * @param dest The destination object into which properties from the source
88 * object will be copied.
116 * object will be copied.
89 * @param source The source of values which will be copied to the destination
117 * @param source The source of values which will be copied to the destination
90 * object.
118 * object.
91 * @param template An optional parameter specifies which properties should be
119 * @param template An optional parameter specifies which properties should be
92 * copied from the source and how to map them to the destination. If the
120 * copied from the source and how to map them to the destination. If the
93 * template is an array it contains the list of property names to copy from the
121 * template is an array it contains the list of property names to copy from the
94 * source to the destination. In case of object the templates contains the map
122 * source to the destination. In case of object the templates contains the map
95 * where keys are property names in the source and the values are property
123 * where keys are property names in the source and the values are property
96 * names in the destination object. If the template isn't specified then the
124 * names in the destination object. If the template isn't specified then the
97 * own properties of the source are entirely copied to the destination.
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 argumentNotNull(dest, "to");
129 argumentNotNull(dest, "to");
102 let _res = <T & S>dest;
130 const _res = dest as T & S;
103
131
104 if (template instanceof Array) {
132 if (template instanceof Array) {
105 for(let i = 0; i < template.length; i++) {
133 for (const p of template) {
106 let p = template[i];
107 if (p in source)
134 if (p in source)
108 _res[p] = source[p];
135 _res[p] = source[p];
109 }
136 }
110 } else if (template) {
137 } else if (template) {
111 let keys = Object.keys(source);
138 const keys = Object.keys(source);
112 for(let i = 0; i < keys.length; i++) {
139 for (const p of keys) {
113 let p = keys[i];
114 if (p in template)
140 if (p in template)
115 _res[template[p]] = source[p];
141 _res[template[p]] = source[p];
116 }
142 }
117 } else {
143 } else {
118 let keys = Object.keys(source);
144 const keys = Object.keys(source);
119 for(let i = 0; i < keys.length; i++) {
145 for (const p of keys)
120 let p = keys[i];
121 _res[p] = source[p];
146 _res[p] = source[p];
122 }
147 }
123 }
124
148
125 return _res;
149 return _res;
126 }
150 }
127
151
128 /** Wraps the specified function to emulate an asynchronous execution.
152 /** Wraps the specified function to emulate an asynchronous execution.
129 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
153 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
130 * @param{Function|String} fn [Required] Function wich will be wrapped.
154 * @param{Function|String} fn [Required] Function wich will be wrapped.
131 */
155 */
132 export function async(_fn: (...args: any[]) => any, thisArg): (...args: any[]) => PromiseLike<any> {
156 export function async(_fn: (...args: any[]) => any, thisArg): (...args: any[]) => PromiseLike<any> {
133 let fn = _fn;
157 let fn = _fn;
134
158
135 if (arguments.length == 2 && !(fn instanceof Function))
159 if (arguments.length === 2 && !(fn instanceof Function))
136 fn = thisArg[fn];
160 fn = thisArg[fn];
137
161
138 if (fn == null)
162 if (fn == null)
139 throw new Error("The function must be specified");
163 throw new Error("The function must be specified");
140
164
141 function wrapresult(x, e?): PromiseLike<any> {
165 function wrapresult(x, e?): PromiseLike<any> {
142 if (e) {
166 if (e) {
143 return {
167 return {
144 then: function (cb, eb) {
168 then(cb, eb) {
145 try {
169 try {
146 return eb ? wrapresult(eb(e)) : this;
170 return eb ? wrapresult(eb(e)) : this;
147 } catch (e2) {
171 } catch (e2) {
148 return wrapresult(null, e2);
172 return wrapresult(null, e2);
149 }
173 }
150 }
174 }
151 };
175 };
152 } else {
176 } else {
153 if (x && x.then)
177 if (x && x.then)
154 return x;
178 return x;
155 return {
179 return {
156 then: function (cb) {
180 then(cb) {
157 try {
181 try {
158 return cb ? wrapresult(cb(x)) : this;
182 return cb ? wrapresult(cb(x)) : this;
159 } catch (e2) {
183 } catch (e2) {
160 return wrapresult(e2);
184 return wrapresult(e2);
161 }
185 }
162 }
186 }
163 };
187 };
164 }
188 }
165 }
189 }
166
190
167 return function () {
191 return (...args) => {
168 try {
192 try {
169 return wrapresult(fn.apply(thisArg, arguments));
193 return wrapresult(fn.apply(thisArg, args));
170 } catch (e) {
194 } catch (e) {
171 return wrapresult(null, e);
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 let method;
203 let method;
178
204
179 if (!(_method instanceof Function)) {
205 if (!(_method instanceof Function)) {
180 argumentNotNull(target, "target");
206 argumentNotNull(target, "target");
181 method = target[_method];
207 method = target[_method];
182 if (!(method instanceof Function))
208 if (!(method instanceof Function))
183 throw new Error("'method' argument must be a Function or a method name");
209 throw new Error("'method' argument must be a Function or a method name");
184 } else {
210 } else {
185 method = _method;
211 method = _method;
186 }
212 }
187
213
188 return function () {
214 return (...args) => {
189 return method.apply(target, arguments);
215 return method.apply(target, args);
190 };
216 };
191 }
217 }
192
218
193 /**
219 /**
194 * Для каждого элемента массива вызывает указанную функцию и сохраняет
220 * Для каждого элемента массива вызывает указанную функцию и сохраняет
195 * возвращенное значение в массиве результатов.
221 * возвращенное значение в массиве результатов.
196 *
222 *
197 * @remarks cb может выполняться асинхронно, при этом одновременно будет
223 * @remarks cb может выполняться асинхронно, при этом одновременно будет
198 * только одна операция.
224 * только одна операция.
199 *
225 *
200 * @async
226 * @async
201 */
227 */
202 export function pmap(items, cb) {
228 export function pmap(items, cb) {
203 argumentNotNull(cb, "cb");
229 argumentNotNull(cb, "cb");
204
230
205 if (items && items.then instanceof Function)
231 if (items && items.then instanceof Function)
206 return items.then(function (data) {
232 return items.then(function (data) {
207 return pmap(data, cb);
233 return pmap(data, cb);
208 });
234 });
209
235
210 if (isNull(items) || !items.length)
236 if (isNull(items) || !items.length)
211 return items;
237 return items;
212
238
213 var i = 0,
239 var i = 0,
214 result = [];
240 result = [];
215
241
216 function next() {
242 function next() {
217 var r, ri;
243 var r, ri;
218
244
219 function chain(x) {
245 function chain(x) {
220 result[ri] = x;
246 result[ri] = x;
221 return next();
247 return next();
222 }
248 }
223
249
224 while (i < items.length) {
250 while (i < items.length) {
225 r = cb(items[i], i);
251 r = cb(items[i], i);
226 ri = i;
252 ri = i;
227 i++;
253 i++;
228 if (r && r.then) {
254 if (r && r.then) {
229 return r.then(chain);
255 return r.then(chain);
230 } else {
256 } else {
231 result[ri] = r;
257 result[ri] = r;
232 }
258 }
233 }
259 }
234 return result;
260 return result;
235 }
261 }
236
262
237 return next();
263 return next();
238 }
264 }
239
265
240 /**
266 /**
241 * Выбирает первый элемент из последовательности, или обещания, если в
267 * Выбирает первый элемент из последовательности, или обещания, если в
242 * качестве параметра используется обещание, оно должно вернуть массив.
268 * качестве параметра используется обещание, оно должно вернуть массив.
243 *
269 *
244 * @param {Function} cb обработчик результата, ему будет передан первый
270 * @param {Function} cb обработчик результата, ему будет передан первый
245 * элемент последовательности в случае успеха
271 * элемент последовательности в случае успеха
246 * @param {Function} err обработчик исключения, если массив пустой, либо
272 * @param {Function} err обработчик исключения, если массив пустой, либо
247 * не массив
273 * не массив
248 *
274 *
249 * @remarks Если не указаны ни cb ни err, тогда функция вернет либо
275 * @remarks Если не указаны ни cb ни err, тогда функция вернет либо
250 * обещание, либо первый элемент.
276 * обещание, либо первый элемент.
251 * @async
277 * @async
252 */
278 */
253 export function first(sequence: any, cb: Function, err: Function) {
279 export function first(sequence: any, cb: Function, err: Function) {
254 if (sequence) {
280 if (sequence) {
255 if (sequence.then instanceof Function) {
281 if (sequence.then instanceof Function) {
256 return sequence.then(function (res) {
282 return sequence.then(function (res) {
257 return first(res, cb, err);
283 return first(res, cb, err);
258 }, err);
284 }, err);
259 } else if (sequence && "length" in sequence) {
285 } else if (sequence && "length" in sequence) {
260 if (sequence.length === 0) {
286 if (sequence.length === 0) {
261 if (err)
287 if (err)
262 return err(new Error("The sequence is empty"));
288 return err(new Error("The sequence is empty"));
263 else
289 else
264 throw new Error("The sequence is empty");
290 throw new Error("The sequence is empty");
265 }
291 }
266 return cb ? cb(sequence[0]) : sequence[0];
292 return cb ? cb(sequence[0]) : sequence[0];
267 }
293 }
268 }
294 }
269
295
270 if (err)
296 if (err)
271 return err(new Error("The sequence is required"));
297 return err(new Error("The sequence is required"));
272 else
298 else
273 throw new Error("The sequence is required");
299 throw new Error("The sequence is required");
274 }
300 }
275
301
276 export function destroy(d: any) {
302 export function destroy(d: any) {
277 if (d && 'destroy' in d)
303 if (d && 'destroy' in d)
278 d.destroy();
304 d.destroy();
279 } No newline at end of file
305 }
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now