##// END OF EJS Templates
Added childContainer service to container services, ServiceContaier is destroyable, fixed browser Uuid version
cin -
r146:f3f5c56d3b3e v1.4.0-rc5 default
parent child
Show More
@@ -1,238 +1,238
1 1 plugins {
2 2 id "org.implab.gradle-typescript" version "1.3.3"
3 3 id "org.implab.gradle-hg"
4 4 id "ivy-publish"
5 5 }
6 6
7 7 if (!symbols in ['local', 'pack', 'none'])
8 8 throw new Exception("The symbols property value is invalid: $symbols");
9 9
10 10 if (!flavour in ['browser', 'node'])
11 11 throw new Exception("The flavour property value is invalid: $flavour");
12 12
13 13 ext {
14 14 packageName = flavour == 'browser' ? "@$npmScope/$name-amd" : "@$npmScope/$name"
15 15 lint = project.hasProperty('lint') ? project.lint ?: true : false
16 16 }
17 17
18 18 sources {
19 19 amd {
20 20 typings {
21 21 srcDir main.output.typingsDir
22 22 }
23 23 }
24 24
25 25 cjs {
26 26 typings {
27 27 srcDir main.output.typingsDir
28 28 }
29 29 }
30 30
31 31 testAmd {
32 32 typings {
33 33 srcDir main.output.typingsDir
34 34 srcDir amd.output.typingsDir
35 35 srcDir test.output.typingsDir
36 36 }
37 37 }
38 38
39 39 testCjs {
40 40 typings {
41 41 srcDir main.output.typingsDir
42 42 srcDir cjs.output.typingsDir
43 43 srcDir test.output.typingsDir
44 44 }
45 45 }
46 46 }
47 47
48 48 typescript {
49 49 compilerOptions {
50 50 types = []
51 51 declaration = true
52 52 experimentalDecorators = true
53 53 strict = true
54 54 // dojo-typings are sick
55 55 skipLibCheck = true
56 56
57 57 if(symbols != 'none') {
58 58 sourceMap = true
59 sourceRoot = packageName
59 sourceRoot = "pack:${packageName}"
60 60 }
61 61
62 62 if (flavour == 'node') {
63 63 module = "commonjs"
64 64 target = "es2017"
65 65 lib = ["es2017", "dom", "scripthost"]
66 66 } else if (flavour == 'browser') {
67 67 module = "amd"
68 68 target = "es5"
69 69 lib = ["es5", "dom", "scripthost", "es2015.promise", "es2015.symbol", "es2015.iterable" ]
70 70 }
71 71 }
72 72 tscCmd = "$projectDir/node_modules/.bin/tsc"
73 73 tsLintCmd = "$projectDir/node_modules/.bin/tslint"
74 74 esLintCmd = "$projectDir/node_modules/.bin/eslint"
75 75 }
76 76
77 77 tasks.matching{ it.name =~ /^lint/ }.configureEach {
78 78 onlyIf { lint }
79 79 }
80 80
81 81 if (symbols == 'local') {
82 82 tasks.matching{ it.name =~ /^configureTs/ }.configureEach {
83 83 compilerOptions {
84 84 sourceRoot = "file://" + it.rootDir
85 85 }
86 86 }
87 87 }
88 88
89 89 task printVersion {
90 90 doLast {
91 91 println "packageName: $packageName";
92 92 println "version: $version";
93 93 println "flavour: $flavour";
94 94 println "target: $typescript.compilerOptions.target";
95 95 println "module: $typescript.compilerOptions.module";
96 96 println "lint: $lint";
97 97 println "symbols: $symbols";
98 98 }
99 99 }
100 100
101 101 npmPackMeta {
102 102 meta {
103 103 name = packageName
104 104 }
105 105 }
106 106
107 107 configureTsCjs {
108 108 dependsOn sources.main.output
109 109 compilerOptions {
110 110 types += [ "node" ]
111 111 }
112 112 }
113 113
114 114 configureTsAmd {
115 115 dependsOn sources.main.output
116 116 compilerOptions {
117 117 types += [ "requirejs", "dojo-typings" ]
118 118 }
119 119 }
120 120
121 121 test {
122 122 workingDir layout.buildDirectory.dir("test");
123 123 commandLine "node", "tests/index.js"
124 124 }
125 125
126 126 assemble {
127 127 if (flavour == 'browser') {
128 128 dependsOn sources.amd.output
129 129 from sources.amd.output.compiledDir
130 130 from sources.amd.resources
131 131 }
132 132 if (flavour == 'node') {
133 133 dependsOn sources.cjs.output
134 134 from sources.cjs.output.compiledDir
135 135 from sources.cjs.resources
136 136 }
137 137 }
138 138
139 139 assembleTest {
140 140 if (flavour == 'browser') {
141 141 dependsOn sources.amd.output, sources.testAmd.output
142 142
143 143 from sources.amd.output.compiledDir
144 144 from sources.testAmd.output.compiledDir
145 145 from sources.amd.resources
146 146 from sources.testAmd.resources
147 147 }
148 148 if (flavour == 'node') {
149 149 dependsOn sources.cjs.output, sources.testCjs.output
150 150
151 151 from sources.cjs.output.compiledDir
152 152 from sources.testCjs.output.compiledDir
153 153 from sources.cjs.resources
154 154 from sources.testCjs.resources
155 155 }
156 156 }
157 157
158 158 typings {
159 159 if (flavour == 'browser') {
160 160 dependsOn sources.amd.output
161 161 from sources.amd.output.typingsDir
162 162 }
163 163 if (flavour == 'node') {
164 164 dependsOn sources.cjs.output
165 165 from sources.cjs.output.typingsDir
166 166 }
167 167 }
168 168
169 169 task npmPackTypings(type: Copy) {
170 170 npmPackContents.dependsOn it
171 171 dependsOn sources.main.output
172 172
173 173 from sources.main.output.typingsDir
174 174
175 175 if (flavour == 'browser') {
176 176 dependsOn sources.amd.output
177 177 from sources.amd.output.typingsDir
178 178 }
179 179 if (flavour == 'node') {
180 180 dependsOn sources.cjs.output
181 181 from sources.cjs.output.typingsDir
182 182 }
183 183
184 184 into npm.packageDir
185 185 }
186 186
187 187 task npmPackSources(type: Copy) {
188 188 from sources.main.ts
189 189 if (symbols == 'pack') {
190 190 npmPackContents.dependsOn npmPackSources
191 191 }
192 192
193 193 if (flavour == 'browser') {
194 194 from sources.amd.ts
195 195 }
196 196 if (flavour == 'node') {
197 197 from sources.cjs.ts
198 198 }
199 199
200 200 into npm.packageDir.dir("_src")
201 201 }
202 202
203 203
204 204
205 205 task packJsTar(type: Tar) {
206 206 dependsOn assemble;
207 207
208 208 archiveBaseName = provider { packageName }
209 209
210 210 destinationDirectory = buildDir
211 211 archiveClassifier = provider { typescript.compilerOptions.module }
212 212 compression = Compression.GZIP
213 213
214 214 from(assemble.outputs)
215 215
216 216 doLast {
217 217 println archiveName;
218 218 }
219 219 }
220 220
221 221 task packTypingsTar(type: Tar) {
222 222 }
223 223
224 224 publishing {
225 225 publications {
226 226 local(IvyPublication) {
227 227 artifact(packJsTar) {
228 228 type = "js"
229 229 }
230 230 }
231 231 }
232 232
233 233 repositories {
234 234 ivy {
235 235 url "ivy-repo"
236 236 }
237 237 }
238 238 } No newline at end of file
@@ -1,288 +1,292
1 1 // Typescript port of the uuid.js
2 2 // Copyright (c) 2018 Sergey Smirnov
3 3 // BSD-2-Clause License https://opensource.org/licenses/BSD-2-Clause
4 4 //
5 5 // uuid.js
6 6 // Copyright (c) 2010-2012 Robert Kieffer
7 7 // MIT License - http://opensource.org/licenses/mit-license.php
8 8
9 9 import { MapOf } from "./interfaces";
10 10
11 11 declare const window: any;
12 12 declare const require: any;
13 13 declare const Buffer: any;
14 14
15 15 const _window: any = "undefined" !== typeof window ? window : null;
16 16
17 function noop(): never {
18 throw new Error();
19 }
20
17 21 interface WritableArrayLike<T> {
18 22 length: number;
19 23 [n: number]: T;
20 24 }
21 25
22 26 // Unique ID creation requires a high quality random # generator. We
23 27 // feature
24 28 // detect to determine the best RNG source, normalizing to a function
25 29 // that
26 30 // returns 128-bits of randomness, since that's what's usually required
27 let _rng: () => WritableArrayLike<number> = () => [];
31 let _rng: () => WritableArrayLike<number> = noop;
28 32
29 33 function setupBrowser() {
30 34 // Allow for MSIE11 msCrypto
31 35 const _crypto = _window.crypto || _window.msCrypto;
32 36
33 if (!_rng && _crypto && _crypto.getRandomValues) {
37 if (_rng === noop && _crypto && _crypto.getRandomValues) {
34 38 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
35 39 //
36 40 // Moderately fast, high quality
37 41 try {
38 42 const _rnds8 = new Uint8Array(16);
39 43 _rng = function whatwgRNG() {
40 44 _crypto.getRandomValues(_rnds8);
41 45 return _rnds8;
42 46 };
43 47 _rng();
44 48 } catch (e) { /**/ }
45 49 }
46 50
47 if (!_rng) {
51 if (_rng === noop) {
48 52 // Math.random()-based (RNG)
49 53 //
50 54 // If all else fails, use Math.random(). It's fast, but is of
51 55 // unspecified
52 56 // quality.
53 57 const _rnds = new Array<number>(16);
54 58 _rng = () => {
55 59 for (let i = 0, r = 0; i < 16; i++) {
56 60 if ((i & 0x03) === 0) {
57 61 r = Math.random() * 0x100000000;
58 62 }
59 63 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
60 64 }
61 65
62 66 return _rnds;
63 67 };
64 68 // if ("undefined" !== typeof console && console.warn) {
65 69 // console.warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()");
66 70 // }
67 71 }
68 72 }
69 73
70 74 function setupNode() {
71 75 // Node.js crypto-based RNG -
72 76 // http://nodejs.org/docs/v0.6.2/api/crypto.html
73 77 //
74 78 // Moderately fast, high quality
75 79 if ("function" === typeof require) {
76 80 try {
77 81 const _rb = require("crypto").randomBytes;
78 82 _rng = _rb && (() => _rb(16));
79 83 _rng();
80 84 } catch (e) { /**/ }
81 85 }
82 86 }
83 87
84 88 if (_window) {
85 89 setupBrowser();
86 90 } else {
87 91 setupNode();
88 92 }
89 93
90 94 // Buffer class to use
91 95 const BufferClass = ("function" === typeof Buffer) ? Buffer : Array;
92 96
93 97 // Maps for number <-> hex string conversion
94 98 const _byteToHex: string[] = [];
95 99 const _hexToByte: MapOf<number> = {};
96 100 for (let i = 0; i < 256; i++) {
97 101 _byteToHex[i] = (i + 0x100).toString(16).substr(1);
98 102 _hexToByte[_byteToHex[i]] = i;
99 103 }
100 104
101 105 // **`parse()` - Parse a UUID into it's component bytes**
102 106 function _parse(s: string, buf: number[] = [], offset?: number): number[] {
103 107 const i = (buf && offset) || 0; let ii = 0;
104 108
105 109 s.toLowerCase().replace(/[0-9a-f]{2}/g, oct => {
106 110 if (ii < 16) { // Don't overflow!
107 111 buf[i + ii++] = _hexToByte[oct];
108 112 }
109 113 return "";
110 114 });
111 115
112 116 // Zero out remaining bytes if string was short
113 117 while (ii < 16) {
114 118 buf[i + ii++] = 0;
115 119 }
116 120
117 121 return buf;
118 122 }
119 123
120 124 // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
121 125 function _unparse(buf: ArrayLike<number>, offset?: number): string {
122 126 let i = offset || 0; const bth = _byteToHex;
123 127 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] +
124 128 bth[buf[i++]] + "-" + bth[buf[i++]] + bth[buf[i++]] + "-" +
125 129 bth[buf[i++]] + bth[buf[i++]] + "-" + bth[buf[i++]] +
126 130 bth[buf[i++]] + "-" + bth[buf[i++]] + bth[buf[i++]] +
127 131 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
128 132 }
129 133
130 134 // **`v1()` - Generate time-based UUID**
131 135 //
132 136 // Inspired by https://github.com/LiosK/UUID.js
133 137 // and http://docs.python.org/library/uuid.html
134 138
135 139 // random #'s we need to init node and clockseq
136 140 const _seedBytes = _rng();
137 141
138 142 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit =
139 143 // 1)
140 144 const _nodeId = [
141 145 _seedBytes[0] | 0x01,
142 146 _seedBytes[1],
143 147 _seedBytes[2],
144 148 _seedBytes[3],
145 149 _seedBytes[4],
146 150 _seedBytes[5]
147 151 ];
148 152
149 153 // Per 4.2.2, randomize (14 bit) clockseq
150 154 let _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
151 155
152 156 // Previous uuid creation time
153 157 let _lastMSecs = 0; let _lastNSecs = 0;
154 158
155 159 interface V1Options {
156 160 clockseq?: number;
157 161 msecs?: number;
158 162 nsecs?: number;
159 163 node?: number[];
160 164 }
161 165
162 166 // See https://github.com/broofa/node-uuid for API details
163 167 function _v1(options?: V1Options): string;
164 168 function _v1(options: V1Options, buf: number[], offset?: number): number[];
165 169 function _v1(options: V1Options = {}, buf?: number[], offset?: number): string | number[] {
166 170 let i = buf && offset || 0;
167 171 const b = buf || [];
168 172
169 173 let clockseq = (options.clockseq != null) ? options.clockseq : _clockseq;
170 174
171 175 // UUID timestamps are 100 nano-second units since the Gregorian
172 176 // epoch,
173 177 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
174 178 // time is handled internally as 'msecs' (integer milliseconds) and
175 179 // 'nsecs'
176 180 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01
177 181 // 00:00.
178 182 let msecs = (options.msecs != null) ? options.msecs : new Date()
179 183 .getTime();
180 184
181 185 // Per 4.2.1.2, use count of uuid's generated during the current
182 186 // clock
183 187 // cycle to simulate higher resolution clock
184 188 let nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1;
185 189
186 190 // Time since last uuid creation (in msecs)
187 191 const dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
188 192
189 193 // Per 4.2.1.2, Bump clockseq on clock regression
190 194 if (dt < 0 && options.clockseq == null) {
191 195 clockseq = clockseq + 1 & 0x3fff;
192 196 }
193 197
194 198 // Reset nsecs if clock regresses (new clockseq) or we've moved onto
195 199 // a new
196 200 // time interval
197 201 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
198 202 nsecs = 0;
199 203 }
200 204
201 205 // Per 4.2.1.2 Throw error if too many uuids are requested
202 206 if (nsecs >= 10000) {
203 207 throw new Error(
204 208 "uuid.v1(): Can't create more than 10M uuids/sec");
205 209 }
206 210
207 211 _lastMSecs = msecs;
208 212 _lastNSecs = nsecs;
209 213 _clockseq = clockseq;
210 214
211 215 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
212 216 msecs += 12219292800000;
213 217
214 218 // `time_low`
215 219 const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
216 220 b[i++] = tl >>> 24 & 0xff;
217 221 b[i++] = tl >>> 16 & 0xff;
218 222 b[i++] = tl >>> 8 & 0xff;
219 223 b[i++] = tl & 0xff;
220 224
221 225 // `time_mid`
222 226 const tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
223 227 b[i++] = tmh >>> 8 & 0xff;
224 228 b[i++] = tmh & 0xff;
225 229
226 230 // `time_high_and_version`
227 231 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
228 232 b[i++] = tmh >>> 16 & 0xff;
229 233
230 234 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
231 235 b[i++] = clockseq >>> 8 | 0x80;
232 236
233 237 // `clock_seq_low`
234 238 b[i++] = clockseq & 0xff;
235 239
236 240 // `node`
237 241 const node = options.node || _nodeId;
238 242 for (let n = 0; n < 6; n++) {
239 243 b[i + n] = node[n];
240 244 }
241 245
242 246 return buf ? buf : _unparse(b);
243 247 }
244 248
245 249 interface V4Opptions {
246 250 rng?: () => WritableArrayLike<number>;
247 251
248 252 random?: number[];
249 253 }
250 254
251 255 // **`v4()` - Generate random UUID**
252 256
253 257 // See https://github.com/broofa/node-uuid for API details
254 258 function _v4(options?: V4Opptions): string;
255 259 function _v4(options: V4Opptions, buf: number[], offset?: number): number[];
256 260 function _v4(options: V4Opptions = {}, buf?: number[], offset?: number): string | number[] {
257 261 // Deprecated - 'format' argument, as supported in v1.2
258 262 const i = buf && offset || 0;
259 263
260 264 const rnds = options.random || (options.rng || _rng)();
261 265
262 266 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
263 267 rnds[6] = (rnds[6] & 0x0f) | 0x40;
264 268 rnds[8] = (rnds[8] & 0x3f) | 0x80;
265 269
266 270 // Copy bytes to buffer, if provided
267 271 if (buf) {
268 272 for (let ii = 0; ii < 16; ii++) {
269 273 buf[i + ii] = rnds[ii];
270 274 }
271 275 }
272 276
273 277 return buf || _unparse(rnds);
274 278 }
275 279
276 280 function _Uuid() {
277 281 return _v4();
278 282 }
279 283
280 284 namespace _Uuid {
281 285 export const v4 = _v4;
282 286 export const v1 = _v1;
283 287 export const empty = "00000000-0000-0000-0000-000000000000";
284 288 export const parse = _parse;
285 289 export const Uuid = _v4;
286 290 }
287 291
288 292 export = _Uuid;
@@ -1,173 +1,174
1 1 import { ActivationContext } from "./ActivationContext";
2 2 import { ValueDescriptor } from "./ValueDescriptor";
3 3 import { ActivationError } from "./ActivationError";
4 4 import { ServiceMap, Descriptor, PartialServiceMap, ContainerServiceMap, ContainerKeys, TypeOfService, ServiceContainer } from "./interfaces";
5 5 import { TraceSource } from "../log/TraceSource";
6 6 import { Configuration, RegistrationMap } from "./Configuration";
7 7 import { Cancellation } from "../Cancellation";
8 import { IDestroyable, ICancellation } from "../interfaces";
8 import { ICancellation } from "../interfaces";
9 9 import { isDescriptor } from "./traits";
10 10 import { LifetimeManager } from "./LifetimeManager";
11 11 import { each, isString } from "../safe";
12 12 import { ContainerConfiguration, FluentRegistrations } from "./fluent/interfaces";
13 13 import { FluentConfiguration } from "./fluent/FluentConfiguration";
14 14
15 15 const trace = TraceSource.get("@implab/core/di/ActivationContext");
16 16
17 export class Container<S extends object = any> implements ServiceContainer<S>, IDestroyable {
17 export class Container<S extends object = any> implements ServiceContainer<S> {
18 18 readonly _services: ContainerServiceMap<S>;
19 19
20 20 readonly _lifetimeManager: LifetimeManager;
21 21
22 22 readonly _cleanup: (() => void)[];
23 23
24 24 readonly _root: Container<S>;
25 25
26 26 readonly _parent?: Container<S>;
27 27
28 28 _disposed: boolean;
29 29
30 30 constructor(parent?: Container<S>) {
31 31 this._parent = parent;
32 this._services = parent ? Object.create(parent._services) : {};
32 this._services = Object.create(parent ? parent._services : null);
33 33 this._cleanup = [];
34 34 this._root = parent ? parent.getRootContainer() : this;
35 35 this._services.container = new ValueDescriptor(this) as any;
36 this._services.childContainer = { activate: () => this.createChildContainer() };
36 37 this._disposed = false;
37 38 this._lifetimeManager = new LifetimeManager();
38 39 }
39 40
40 41 getRootContainer() {
41 42 return this._root;
42 43 }
43 44
44 45 getParent() {
45 46 return this._parent;
46 47 }
47 48
48 49 getLifetimeManager() {
49 50 return this._lifetimeManager;
50 51 }
51 52
52 53 resolve<K extends ContainerKeys<S>>(name: K, def?: TypeOfService<S, K>): TypeOfService<S, K> {
53 54 trace.debug("resolve {0}", name);
54 55 const d = this._services[name];
55 56 if (d === undefined) {
56 57 if (def !== undefined)
57 58 return def;
58 59 else
59 60 throw new Error("Service '" + name + "' isn't found");
60 61 } else {
61 62
62 63 const context = new ActivationContext<S>(this, this._services, String(name), d);
63 64 try {
64 65 return d.activate(context);
65 66 } catch (error) {
66 67 throw new ActivationError(name.toString(), context.getStack(), error);
67 68 }
68 69 }
69 70 }
70 71
71 72 /**
72 73 * @deprecated use resolve() method
73 74 */
74 75 getService<K extends ContainerKeys<S>>(name: K, def?: TypeOfService<S, K>) {
75 76 return this.resolve(name, def);
76 77 }
77 78
78 79 register<K extends keyof S>(name: K, service: Descriptor<S, S[K]>): this;
79 80 register(services: PartialServiceMap<S>): this;
80 81 register<K extends keyof S>(nameOrCollection: K | ServiceMap<S>, service?: Descriptor<S, S[K]>) {
81 82 if (arguments.length === 1) {
82 83 const data = nameOrCollection as ServiceMap<S>;
83 84
84 85 each(data, (v, k) => this.register(k, v));
85 86 } else {
86 87 if (!isDescriptor(service))
87 88 throw new Error("The service parameter must be a descriptor");
88 89
89 90 this._services[nameOrCollection as K] = service as any;
90 91 }
91 92 return this;
92 93 }
93 94
94 95 /** @deprecated use getLifetimeManager() */
95 96 onDispose(callback: () => void) {
96 97 if (!(callback instanceof Function))
97 98 throw new Error("The callback must be a function");
98 99 this._cleanup.push(callback);
99 100 }
100 101
101 102 destroy() {
102 103 return this.dispose();
103 104 }
104 105 dispose() {
105 106 if (this._disposed)
106 107 return;
107 108 this._disposed = true;
108 109 for (const f of this._cleanup)
109 110 f();
110 111 }
111 112
112 113 /**
113 114 * @param{String|Object} config
114 115 * The configuration of the container. Can be either a string or an object,
115 116 * if the configuration is an object it's treated as a collection of
116 117 * services which will be registered in the container.
117 118 *
118 119 * @param{Function} opts.contextRequire
119 120 * The function which will be used to load a configuration or types for services.
120 121 *
121 122 */
122 123 async configure(config: string | RegistrationMap<S>, opts?: { contextRequire: any; baseModule?: string }, ct = Cancellation.none) {
123 124 const _opts = Object.create(opts || null);
124 125
125 126 if (typeof (config) === "string") {
126 127 _opts.baseModule = config;
127 128
128 129 const module = await import(config);
129 130 if (module && module.default && typeof (module.default.apply) === "function")
130 131 return module.default.apply(this);
131 132 else
132 133 return this._applyLegacyConfig(module, _opts, ct);
133 134 } else {
134 135 return this._applyLegacyConfig(config, _opts, ct);
135 136 }
136 137 }
137 138
138 139 applyConfig<S2 extends object>(config: Promise<{ default: ContainerConfiguration<S2>; }>, ct?: ICancellation): Promise<ServiceContainer<S & S2>>;
139 140 applyConfig<S2 extends object, P extends string>(config: Promise<{ [p in P]: ContainerConfiguration<S2>; }>, prop: P, ct?: ICancellation): Promise<ServiceContainer<S & S2>>;
140 141 async applyConfig<S2 extends object, P extends string>(
141 142 config: Promise<{ [p in P | "default"]: ContainerConfiguration<S2>; }>,
142 143 propOrCt?: P | ICancellation,
143 144 ct?: ICancellation
144 145 ): Promise<ServiceContainer<S & S2>> {
145 146 const mod = await config;
146 147
147 148 let _ct: ICancellation;
148 149 let _prop: P | "default";
149 150
150 151 if (isString(propOrCt)) {
151 152 _prop = propOrCt;
152 153 _ct = ct || Cancellation.none;
153 154 } else {
154 155 _ct = propOrCt || Cancellation.none;
155 156 _prop = "default";
156 157 }
157 158
158 159 return mod[_prop].apply(this, _ct);
159 160 }
160 161
161 162 async _applyLegacyConfig(config: RegistrationMap<S>, opts: { contextRequire: any; baseModule?: string }, ct = Cancellation.none) {
162 163 return new Configuration<S>(this).applyConfiguration(config, opts);
163 164 }
164 165
165 166 async fluent<K extends keyof S>(config: FluentRegistrations<K, S>, ct = Cancellation.none): Promise<this> {
166 167 await new FluentConfiguration<S>().register(config).apply(this, ct);
167 168 return this;
168 169 }
169 170
170 171 createChildContainer<S2 extends object = S>(): Container<S & S2> {
171 172 return new Container<S & S2>(this as any);
172 173 }
173 174 }
@@ -1,62 +1,65
1 import { IDestroyable } from "../interfaces";
1 2 import { ActivationContext } from "./ActivationContext";
2 3 import { LifetimeManager } from "./LifetimeManager";
3 4
4 5 export interface Descriptor<S extends object = any, T = any> {
5 6 activate(context: ActivationContext<S>): T;
6 7 }
7 8
8 9 export type ServiceMap<S extends object> = {
9 10 [k in keyof S]: Descriptor<S, S[k]>;
10 11 };
11 12
12 13 export type ContainerKeys<S extends object> = keyof S | keyof ContainerProvided<S>;
13 14
14 15 export type TypeOfService<S extends object, K> =
15 16 K extends keyof ContainerProvided<S> ? ContainerProvided<S>[K] :
16 17 K extends keyof S ? S[K] : never;
17 18
18 19 export type ContainerServiceMap<S extends object> = {
19 20 [K in ContainerKeys<S>]: Descriptor<S, TypeOfService<S, K>>;
20 21 };
21 22
22 23 export type PartialServiceMap<S extends object> = {
23 24 [k in keyof S]?: Descriptor<S, S[k]>;
24 25 };
25 26
26 27 export interface ServiceLocator<S extends object> {
27 28 resolve<K extends ContainerKeys<S>>(name: K, def?: TypeOfService<S, K>): TypeOfService<S, K>;
28 29 }
29 30
30 export interface ServiceContainer<S extends object> extends ServiceLocator<S> {
31 export interface ServiceContainer<S extends object> extends ServiceLocator<S>, IDestroyable {
31 32 getLifetimeManager(): LifetimeManager;
32 33 register<K extends keyof S>(name: K, service: Descriptor<S, S[K]>): this;
33 34 register(services: PartialServiceMap<S>): this;
34 35
35 36 createChildContainer(): ServiceContainer<S>;
36 37 }
37 38
38 39 export interface ContainerProvided<S extends object> {
39 40 container: ServiceLocator<S>;
41
42 childContainer: ServiceContainer<S>;
40 43 }
41 44
42 45 export type ContainerRegistered<S extends object> = /*{
43 46 [K in Exclude<keyof S, keyof ContainerProvided<S>>]: S[K];
44 47 };*/
45 48 Exclude<S, ContainerProvided<S>>;
46 49
47 50 export type ActivationType = "singleton" | "container" | "hierarchy" | "context" | "call";
48 51
49 52 /**
50 53 * Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ для управлСния Тизнью экзСмпляра ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. КаТдая рСгистрация ΠΈΠΌΠ΅Π΅Ρ‚
51 54 * свой собствСнный ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ `ILifetime`, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ создаСтся ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΉ Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ
52 55 */
53 56 export interface ILifetime {
54 57 /** ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ ΡƒΠΆΠ΅ создан экзСмпляр ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° */
55 58 has(): boolean;
56 59
57 60 get(): any;
58 61
59 62 initialize(context: ActivationContext<any>): void;
60 63
61 64 store(item: any, cleanup?: (item: any) => void): void;
62 65 }
@@ -1,86 +1,95
1 1 import { StringBuilder } from "../text/StringBuilder";
2 2 import { test } from "./TestTraits";
3 3 import { MockConsole } from "../mock/MockConsole";
4 4 import { ConsoleWriter } from "../log/ConsoleWriter";
5 import { Uuid } from "../Uuid";
5 6
6 7 test("String builder", async t => {
7 8 const sb = new StringBuilder();
8 9
9 10 sb.write("hello");
10 11 t.equals(sb.toString(), "hello", "Write simple text");
11 12
12 13 sb.write(", ");
13 14 sb.write("world!");
14 15 t.equals(sb.toString(), "hello, world!", "Append text");
15 16
16 17 sb.clear();
17 18 t.equals(sb.toString(), "", "Clear");
18 19
19 20 sb.write(1);
20 21 t.equals(sb.toString(), "1", "Write number");
21 22
22 23 sb.clear();
23 24 sb.writeValue(0.123);
24 25 t.equals(sb.toString(), "0.123", "Format number");
25 26
26 27 sb.clear();
27 28 sb.writeValue(new Date("2019-01-02T00:00:00.000Z"));
28 29 t.equals(sb.toString(), "2019-01-02T00:00:00.000Z", "Format date (ISO)");
29 30
30 31 sb.clear();
31 32 sb.write("{0}", "hello");
32 33 t.equals(sb.toString(), "hello", "Simple format text");
33 34
34 35 sb.write(", {0}!", "world");
35 36 t.equals(sb.toString(), "hello, world!", "Append formatted text");
36 37
37 38 sb.clear();
38 39 sb.write("abc: {0:json}; {0.length}; {0.1} {{olo}}", ["a", "b", "c"]);
39 40 t.equals(sb.toString(), 'abc: [\n "a",\n "b",\n "c"\n]; 3; b {olo}', "Format string with spec");
40 41
41 42 sb.clear();
42 43 t.throws(() => sb.write("}", 0), "Should die on bad format: '}'");
43 44 t.throws(() => sb.write("{", 0), "Should die on bad format: '{'");
44 45 t.throws(() => sb.write("{}", 0), "Should die on bad format: '{}'");
45 46 t.throws(() => sb.write("{:}", 0), "Should die on bad format: '{:}'");
46 47 t.throws(() => sb.write("{{0}", 0), "Should die on bad format: '{{0}'");
47 48
48 49 });
49 50
50 51 test("ConsoleWriter", t => {
51 52 const mockConsole = new MockConsole();
52 53 const writer = new ConsoleWriter(mockConsole);
53 54
54 55 writer.setLogLevel("log");
55 56
56 57 writer.writeLine("Hello, world!");
57 58
58 59 t.equals(mockConsole.getBuffer().length, 1, "One line should be written");
59 60 t.equals(mockConsole.getBuffer()[0].level, "log", "LogLevel should be 'log'");
60 61 t.deepEqual(mockConsole.getBuffer()[0].data, ["Hello, world!"], "The buffer should contain single string");
61 62
62 63 mockConsole.clear();
63 64 writer.setLogLevel("debug");
64 65 writer.write("Bring ");
65 66 writer.write("the {0}!", "light");
66 67 t.equals(mockConsole.getBuffer().length, 0, "No line should be written");
67 68 writer.writeLine();
68 69
69 70 t.equals(mockConsole.getBuffer().length, 1, "One line should be written");
70 71 t.equals(mockConsole.getBuffer()[0].level, "debug", "LogLevel should be 'log'");
71 72 t.deepEqual(mockConsole.getBuffer()[0].data, ["Bring the light!"], "Should concatenate string parts together");
72 73
73 74 mockConsole.clear();
74 75 writer.writeLine("It's {0} o'clock, lets have some {1}!", { h: 5}, { title: "tee" });
75 76
76 77 t.deepEqual(mockConsole.getBuffer()[0].data, ["It's ", { h: 5}, " o'clock, lets have some ", { title: "tee" }, "!"], "Non string parts should be psassed as is");
77 78
78 79 mockConsole.clear();
79 80 writer.writeLine("{0} or {1} to {2}", {i: 25}, 6, 4);
80 81 t.deepEqual(mockConsole.getBuffer()[0].data, [{i: 25}, " or 6 to 4"], "25 or 6 to 4");
81 82
82 83 mockConsole.clear();
83 84 writer.writeLine("{0} or {1} to {2}! Let's have some {3}", 25, 6, 4, { product: "tee" } );
84 85 t.deepEqual(mockConsole.getBuffer()[0].data, ["25 or 6 to 4! Let's have some ", { product: "tee" }], "Should handle many text chunks and object at the end");
85 86
86 87 });
88
89 test("Uuid test", (t, log) => {
90 const id = Uuid();
91 log.log("uuid = {0}", id);
92 t.assert(id, "Should generate uuid");
93 t.notEqual(id, Uuid(), "uuid should never match");
94
95 });
General Comments 0
You need to be logged in to leave comments. Login now