##// END OF EJS Templates
tests
cin -
r41:eae7e609c38a di-typescript
parent child
Show More
@@ -0,0 +1,3
1 export class Bar {
2 name = "bar";
3 }
@@ -0,0 +1,3
1 export class Foo {
2 name = "foo";
3 }
@@ -1,22 +1,22
1 Copyright 2017-2018 Implab team
1 Copyright 2017-2019 Implab team
2 2
3 3 Redistribution and use in source and binary forms, with or without
4 4 modification, are permitted provided that the following conditions are met:
5 5
6 6 1. Redistributions of source code must retain the above copyright notice, this
7 7 list of conditions and the following disclaimer.
8 8
9 9 2. Redistributions in binary form must reproduce the above copyright notice,
10 10 this list of conditions and the following disclaimer in the documentation
11 11 and/or other materials provided with the distribution.
12 12
13 13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 16 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17 17 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 18 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 19 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 20 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 21 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 22 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. No newline at end of file
@@ -1,449 +1,449
1 1 {
2 2 "name": "@implab/core",
3 3 "version": "0.0.1-dev",
4 4 "lockfileVersion": 1,
5 5 "requires": true,
6 6 "dependencies": {
7 7 "@types/node": {
8 8 "version": "10.12.12",
9 9 "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.12.tgz",
10 10 "integrity": "sha512-Pr+6JRiKkfsFvmU/LK68oBRCQeEg36TyAbPhc2xpez24OOZZCuoIhWGTd39VZy6nGafSbxzGouFPTFD/rR1A0A==",
11 11 "dev": true
12 12 },
13 13 "@types/tape": {
14 14 "version": "4.2.32",
15 15 "resolved": "http://registry.npmjs.org/@types/tape/-/tape-4.2.32.tgz",
16 16 "integrity": "sha512-xil0KO5wkPoixdBWGIGolPv9dekf6dVkjjJLAFYchfKcd4DICou67rgGCIO7wAh3i5Ff/6j9IDgZz+GU9cMaqQ==",
17 17 "dev": true,
18 18 "requires": {
19 19 "@types/node": "*"
20 20 }
21 21 },
22 22 "balanced-match": {
23 23 "version": "1.0.0",
24 24 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
25 25 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
26 26 "dev": true
27 27 },
28 28 "brace-expansion": {
29 29 "version": "1.1.11",
30 30 "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
31 31 "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
32 32 "dev": true,
33 33 "requires": {
34 34 "balanced-match": "^1.0.0",
35 35 "concat-map": "0.0.1"
36 36 }
37 37 },
38 38 "concat-map": {
39 39 "version": "0.0.1",
40 40 "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
41 41 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
42 42 "dev": true
43 43 },
44 44 "core-util-is": {
45 45 "version": "1.0.2",
46 46 "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
47 47 "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
48 48 "dev": true
49 49 },
50 50 "deep-equal": {
51 51 "version": "0.1.2",
52 52 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.1.2.tgz",
53 53 "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=",
54 54 "dev": true
55 55 },
56 56 "define-properties": {
57 57 "version": "1.1.3",
58 58 "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
59 59 "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
60 60 "dev": true,
61 61 "requires": {
62 62 "object-keys": "^1.0.12"
63 63 },
64 64 "dependencies": {
65 65 "object-keys": {
66 66 "version": "1.0.12",
67 67 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
68 68 "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
69 69 "dev": true
70 70 }
71 71 }
72 72 },
73 73 "defined": {
74 74 "version": "0.0.0",
75 75 "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz",
76 76 "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=",
77 77 "dev": true
78 78 },
79 79 "dojo": {
80 80 "version": "1.13.0",
81 81 "resolved": "https://registry.npmjs.org/dojo/-/dojo-1.13.0.tgz",
82 82 "integrity": "sha512-mGoGvsXAbPkUrBnxCoO7m6CFH8jvWq7rAL7fP7jrhJEOyswA/bZwWdXwEH0ovs68t8S0+xOpV/3V7addYbaiAA=="
83 83 },
84 84 "duplexer": {
85 85 "version": "0.1.1",
86 "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
86 "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
87 87 "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
88 88 "dev": true
89 89 },
90 90 "es-abstract": {
91 91 "version": "1.12.0",
92 92 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
93 93 "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
94 94 "dev": true,
95 95 "requires": {
96 96 "es-to-primitive": "^1.1.1",
97 97 "function-bind": "^1.1.1",
98 98 "has": "^1.0.1",
99 99 "is-callable": "^1.1.3",
100 100 "is-regex": "^1.0.4"
101 101 }
102 102 },
103 103 "es-to-primitive": {
104 104 "version": "1.2.0",
105 105 "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
106 106 "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
107 107 "dev": true,
108 108 "requires": {
109 109 "is-callable": "^1.1.4",
110 110 "is-date-object": "^1.0.1",
111 111 "is-symbol": "^1.0.2"
112 112 }
113 113 },
114 114 "faucet": {
115 115 "version": "0.0.1",
116 116 "resolved": "https://registry.npmjs.org/faucet/-/faucet-0.0.1.tgz",
117 117 "integrity": "sha1-WX3PHSGJosBiMhtZHo8VHtIDnZw=",
118 118 "dev": true,
119 119 "requires": {
120 120 "defined": "0.0.0",
121 121 "duplexer": "~0.1.1",
122 122 "minimist": "0.0.5",
123 123 "sprintf": "~0.1.3",
124 124 "tap-parser": "~0.4.0",
125 125 "tape": "~2.3.2",
126 126 "through2": "~0.2.3"
127 127 },
128 128 "dependencies": {
129 129 "tape": {
130 130 "version": "2.3.3",
131 "resolved": "http://registry.npmjs.org/tape/-/tape-2.3.3.tgz",
131 "resolved": "https://registry.npmjs.org/tape/-/tape-2.3.3.tgz",
132 132 "integrity": "sha1-Lnzgox3wn41oUWZKcYQuDKUFevc=",
133 133 "dev": true,
134 134 "requires": {
135 135 "deep-equal": "~0.1.0",
136 136 "defined": "~0.0.0",
137 137 "inherits": "~2.0.1",
138 138 "jsonify": "~0.0.0",
139 139 "resumer": "~0.0.0",
140 140 "through": "~2.3.4"
141 141 }
142 142 }
143 143 }
144 144 },
145 145 "for-each": {
146 146 "version": "0.3.3",
147 147 "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
148 148 "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
149 149 "dev": true,
150 150 "requires": {
151 151 "is-callable": "^1.1.3"
152 152 }
153 153 },
154 154 "fs.realpath": {
155 155 "version": "1.0.0",
156 156 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
157 157 "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
158 158 "dev": true
159 159 },
160 160 "function-bind": {
161 161 "version": "1.1.1",
162 162 "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
163 163 "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
164 164 "dev": true
165 165 },
166 166 "glob": {
167 167 "version": "7.1.3",
168 168 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
169 169 "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
170 170 "dev": true,
171 171 "requires": {
172 172 "fs.realpath": "^1.0.0",
173 173 "inflight": "^1.0.4",
174 174 "inherits": "2",
175 175 "minimatch": "^3.0.4",
176 176 "once": "^1.3.0",
177 177 "path-is-absolute": "^1.0.0"
178 178 }
179 179 },
180 180 "has": {
181 181 "version": "1.0.3",
182 182 "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
183 183 "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
184 184 "dev": true,
185 185 "requires": {
186 186 "function-bind": "^1.1.1"
187 187 }
188 188 },
189 189 "has-symbols": {
190 190 "version": "1.0.0",
191 191 "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
192 192 "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
193 193 "dev": true
194 194 },
195 195 "inflight": {
196 196 "version": "1.0.6",
197 197 "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
198 198 "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
199 199 "dev": true,
200 200 "requires": {
201 201 "once": "^1.3.0",
202 202 "wrappy": "1"
203 203 }
204 204 },
205 205 "inherits": {
206 206 "version": "2.0.3",
207 207 "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
208 208 "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
209 209 "dev": true
210 210 },
211 211 "is-callable": {
212 212 "version": "1.1.4",
213 213 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
214 214 "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
215 215 "dev": true
216 216 },
217 217 "is-date-object": {
218 218 "version": "1.0.1",
219 219 "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
220 220 "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
221 221 "dev": true
222 222 },
223 223 "is-regex": {
224 224 "version": "1.0.4",
225 225 "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
226 226 "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
227 227 "dev": true,
228 228 "requires": {
229 229 "has": "^1.0.1"
230 230 }
231 231 },
232 232 "is-symbol": {
233 233 "version": "1.0.2",
234 234 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
235 235 "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
236 236 "dev": true,
237 237 "requires": {
238 238 "has-symbols": "^1.0.0"
239 239 }
240 240 },
241 241 "isarray": {
242 242 "version": "0.0.1",
243 243 "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
244 244 "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
245 245 "dev": true
246 246 },
247 247 "jsonify": {
248 248 "version": "0.0.0",
249 249 "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
250 250 "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
251 251 "dev": true
252 252 },
253 253 "minimatch": {
254 254 "version": "3.0.4",
255 255 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
256 256 "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
257 257 "dev": true,
258 258 "requires": {
259 259 "brace-expansion": "^1.1.7"
260 260 }
261 261 },
262 262 "minimist": {
263 263 "version": "0.0.5",
264 264 "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz",
265 265 "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=",
266 266 "dev": true
267 267 },
268 268 "object-inspect": {
269 269 "version": "1.6.0",
270 270 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
271 271 "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==",
272 272 "dev": true
273 273 },
274 274 "object-keys": {
275 275 "version": "0.4.0",
276 276 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
277 277 "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
278 278 "dev": true
279 279 },
280 280 "once": {
281 281 "version": "1.4.0",
282 282 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
283 283 "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
284 284 "dev": true,
285 285 "requires": {
286 286 "wrappy": "1"
287 287 }
288 288 },
289 289 "path-is-absolute": {
290 290 "version": "1.0.1",
291 "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
291 "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
292 292 "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
293 293 "dev": true
294 294 },
295 295 "path-parse": {
296 296 "version": "1.0.6",
297 297 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
298 298 "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
299 299 "dev": true
300 300 },
301 301 "readable-stream": {
302 302 "version": "1.1.14",
303 "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
303 "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
304 304 "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
305 305 "dev": true,
306 306 "requires": {
307 307 "core-util-is": "~1.0.0",
308 308 "inherits": "~2.0.1",
309 309 "isarray": "0.0.1",
310 310 "string_decoder": "~0.10.x"
311 311 }
312 312 },
313 313 "requirejs": {
314 314 "version": "2.3.6",
315 315 "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
316 316 "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
317 317 "dev": true
318 318 },
319 319 "resolve": {
320 320 "version": "1.7.1",
321 321 "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
322 322 "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
323 323 "dev": true,
324 324 "requires": {
325 325 "path-parse": "^1.0.5"
326 326 }
327 327 },
328 328 "resumer": {
329 329 "version": "0.0.0",
330 330 "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz",
331 331 "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=",
332 332 "dev": true,
333 333 "requires": {
334 334 "through": "~2.3.4"
335 335 }
336 336 },
337 337 "sprintf": {
338 338 "version": "0.1.5",
339 339 "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz",
340 340 "integrity": "sha1-j4PjmpMXwaUCy324BQ5Rxnn27c8=",
341 341 "dev": true
342 342 },
343 343 "string.prototype.trim": {
344 344 "version": "1.1.2",
345 345 "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz",
346 346 "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=",
347 347 "dev": true,
348 348 "requires": {
349 349 "define-properties": "^1.1.2",
350 350 "es-abstract": "^1.5.0",
351 351 "function-bind": "^1.0.2"
352 352 }
353 353 },
354 354 "string_decoder": {
355 355 "version": "0.10.31",
356 "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
356 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
357 357 "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
358 358 "dev": true
359 359 },
360 360 "tap-parser": {
361 361 "version": "0.4.3",
362 362 "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-0.4.3.tgz",
363 363 "integrity": "sha1-pOrhkMENdsehEZIf84u+TVjwnuo=",
364 364 "dev": true,
365 365 "requires": {
366 366 "inherits": "~2.0.1",
367 367 "readable-stream": "~1.1.11"
368 368 }
369 369 },
370 370 "tape": {
371 371 "version": "4.9.1",
372 372 "resolved": "https://registry.npmjs.org/tape/-/tape-4.9.1.tgz",
373 373 "integrity": "sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw==",
374 374 "dev": true,
375 375 "requires": {
376 376 "deep-equal": "~1.0.1",
377 377 "defined": "~1.0.0",
378 378 "for-each": "~0.3.3",
379 379 "function-bind": "~1.1.1",
380 380 "glob": "~7.1.2",
381 381 "has": "~1.0.3",
382 382 "inherits": "~2.0.3",
383 383 "minimist": "~1.2.0",
384 384 "object-inspect": "~1.6.0",
385 385 "resolve": "~1.7.1",
386 386 "resumer": "~0.0.0",
387 387 "string.prototype.trim": "~1.1.2",
388 388 "through": "~2.3.8"
389 389 },
390 390 "dependencies": {
391 391 "deep-equal": {
392 392 "version": "1.0.1",
393 393 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
394 394 "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
395 395 "dev": true
396 396 },
397 397 "defined": {
398 398 "version": "1.0.0",
399 399 "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
400 400 "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
401 401 "dev": true
402 402 },
403 403 "minimist": {
404 404 "version": "1.2.0",
405 405 "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
406 406 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
407 407 "dev": true
408 408 }
409 409 }
410 410 },
411 411 "through": {
412 412 "version": "2.3.8",
413 "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
413 "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
414 414 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
415 415 "dev": true
416 416 },
417 417 "through2": {
418 418 "version": "0.2.3",
419 "resolved": "http://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
419 "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
420 420 "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
421 421 "dev": true,
422 422 "requires": {
423 423 "readable-stream": "~1.1.9",
424 424 "xtend": "~2.1.1"
425 425 }
426 426 },
427 427 "typescript": {
428 428 "version": "3.2.1",
429 429 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.1.tgz",
430 430 "integrity": "sha512-jw7P2z/h6aPT4AENXDGjcfHTu5CSqzsbZc6YlUIebTyBAq8XaKp78x7VcSh30xwSCcsu5irZkYZUSFP1MrAMbg==",
431 431 "dev": true
432 432 },
433 433 "wrappy": {
434 434 "version": "1.0.2",
435 435 "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
436 436 "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
437 437 "dev": true
438 438 },
439 439 "xtend": {
440 440 "version": "2.1.2",
441 441 "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
442 442 "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
443 443 "dev": true,
444 444 "requires": {
445 445 "object-keys": "~0.4.0"
446 446 }
447 447 }
448 448 }
449 449 }
@@ -1,134 +1,132
1 1 import { TraceSource } from "../log/TraceSource";
2 2 import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "../safe";
3 3 import { Descriptor, ServiceMap, isDescriptor } from "./interfaces";
4 4 import { Container } from "./Container";
5 5
6 6 const trace = TraceSource.get("@implab/core/di/ActivationContext");
7 7
8 8 export interface ActivationContextInfo {
9 9 name: string;
10 10
11 service: Descriptor;
11 service: string;
12 12
13 13 scope: ServiceMap;
14 14 }
15 15
16 16 export class ActivationContext {
17 17 _cache: object;
18 18
19 19 _services: ServiceMap;
20 20
21 21 _stack: ActivationContextInfo[];
22 22
23 23 _visited: object;
24 24
25 _name: string;
26
27 _localized: boolean;
28
25 29 container: Container;
26 30
27 constructor(container: Container, services: ServiceMap, cache?: object, visited?) {
31 constructor(container: Container, services: ServiceMap, name?: string, cache?: object, visited?) {
28 32 argumentNotNull(container, "container");
29 33 argumentNotNull(services, "services");
30 34
35 this._name = name;
31 36 this._visited = visited || {};
32 37 this._stack = [];
33 38 this._cache = cache || {};
34 39 this._services = services;
35 40 this.container = container;
36 41 }
37 42
38 getService(name, def?): any {
43 getName() {
44 return this._name;
45 }
46
47 resolve(name, def?): any {
39 48 const d = this._services[name];
40 49
41 50 if (!d)
42 51 if (arguments.length > 1)
43 52 return def;
44 53 else
45 54 throw new Error(`Service ${name} not found`);
46 55
47 return isDescriptor(d) ? d.activate(this, name) : d;
56 return this.activate(d, name);
48 57 }
49 58
50 59 /**
51 60 * registers services local to the the activation context
52 61 *
53 62 * @name{string} the name of the service
54 63 * @service{string} the service descriptor to register
55 64 */
56 65 register(name: string, service: Descriptor) {
57 66 argumentNotEmptyString(name, "name");
58 67
59 68 this._services[name] = service;
60 69 }
61 70
62 71 clone() {
63 72 return new ActivationContext(
64 73 this.container,
65 Object.create(this._services),
74 this._services,
75 this._name,
66 76 this._cache,
67 77 this._visited
68 78 );
69 79 }
70 80
71 81 has(id: string) {
72 82 return id in this._cache;
73 83 }
74 84
75 85 get(id: string) {
76 86 return this._cache[id];
77 87 }
78 88
79 89 store(id: string, value) {
80 90 return (this._cache[id] = value);
81 91 }
82 92
83 parse(data, name: string) {
84 if (isPrimitive(data))
85 return data;
93 activate(d: Descriptor, name: string) {
94 if (trace.isLogEnabled())
95 trace.log(`enter ${name} ${d}`);
86 96
87 if (isDescriptor(data)) {
88 return data.activate(this, name);
89 } else if (data instanceof Array) {
90 this.enter(name);
91 const v = data.map( (x, i) => this.parse(x, `[${i}]`));
92 this.leave();
93 return v;
94 } else {
95 this.enter(name);
96 const result = {};
97 for (const p in data)
98 result[p] = this.parse(data[p], "." + p);
99 this.leave();
100 return result;
101 }
97 this.enter(name, d.toString());
98 const v = d.activate(this);
99 this.leave();
100
101 if (trace.isLogEnabled())
102 trace.log(`leave ${name}`);
103
104 return v;
102 105 }
103 106
104 107 visit(id: string) {
105 108 const count = this._visited[id] || 0;
106 109 this._visited[id] = count + 1;
107 110 return count;
108 111 }
109 112
110 113 getStack() {
111 114 return this._stack.slice().reverse();
112 115 }
113 116
114 enter(name: string, d?: Descriptor, localize?: boolean) {
115 if (trace.isLogEnabled())
116 trace.log("enter " + name + " " + (d || "") +
117 (localize ? " localize" : ""));
117 private enter(name: string, service: string) {
118 118 this._stack.push({
119 119 name,
120 service: d,
120 service,
121 121 scope: this._services
122 122 });
123 if (localize)
124 this._services = Object.create(this._services);
123 this._name = name;
124 this._services = Object.create(this._services);
125 125 }
126 126
127 leave() {
127 private leave() {
128 128 const ctx = this._stack.pop();
129 129 this._services = ctx.scope;
130
131 if (trace.isLogEnabled())
132 trace.log("leave " + ctx.name + " " + (ctx.service || ""));
130 this._name = ctx.name;
133 131 }
134 132 }
@@ -1,36 +1,36
1 1 import { ActivationContextInfo } from "./ActivationContext";
2 2
3 3 export class ActivationError {
4 4 activationStack: ActivationContextInfo[];
5 5
6 6 service: string;
7 7
8 8 innerException: any;
9 9
10 10 message: string;
11 11
12 12 constructor(service: string, activationStack: ActivationContextInfo[], innerException) {
13 13 this.message = "Failed to activate the service";
14 14 this.activationStack = activationStack;
15 15 this.service = service;
16 16 this.innerException = innerException;
17 17 }
18 18
19 19 toString() {
20 20 const parts = [this.message];
21 21 if (this.service)
22 22 parts.push("when activating: " + this.service.toString());
23 23
24 24 if (this.innerException)
25 25 parts.push("caused by: " + this.innerException.toString());
26 26
27 27 if (this.activationStack) {
28 28 parts.push("at");
29 29 this.activationStack
30 .forEach(x => parts.push(` ${x.name} ${x.service ? x.service.toString() : ""}`));
30 .forEach(x => parts.push(` ${x.name} ${x.service}`));
31 31
32 32 }
33 33
34 34 return parts.join("\n");
35 35 }
36 36 }
@@ -1,24 +1,37
1 import { Descriptor } from "./interfaces";
1 import { Descriptor, isDescriptor } from "./interfaces";
2 2 import { ActivationContext } from "./ActivationContext";
3 import { isPrimitive } from "util";
3 4
4 5 export class AggregateDescriptor implements Descriptor {
5 6 _value: object;
6 7
7 8 constructor(value: object) {
8 9 this._value = value;
9 10 }
10 11
11 activate(context: ActivationContext, name: string) {
12 context.enter(name);
13 const v = context.parse(this._value, ".params");
14 context.leave();
15 return v;
12 activate(context: ActivationContext) {
13 return this._parse(this._value, context, "$value");
16 14 }
17 15
18 isInstanceCreated(): boolean {
19 return false;
16 // TODO: make async
17 _parse(value, context: ActivationContext, path: string) {
18 if (isPrimitive(value))
19 return value;
20
21 if (isDescriptor(value))
22 return context.activate(value, path);
23
24 if (value instanceof Array)
25 return value.map((x, i) => this._parse(x, context, `${path}[${i}]`));
26
27 const t = {};
28 for (const p of Object.keys(value))
29 t[p] = this._parse(value[p], context, `${path}.${p}`);
30 return t;
31
20 32 }
21 getInstance(): any {
22 throw new Error("Not supported");
33
34 toString() {
35 return "@walk";
23 36 }
24 37 }
@@ -1,260 +1,279
1 1 import { ActivationContext } from "./ActivationContext";
2 2 import { ValueDescriptor } from "./ValueDescriptor";
3 3 import { ActivationError } from "./ActivationError";
4 import { isDescriptor, ActivationType, ServiceMap, isDependencyRegistration, isValueRegistration, ServiceRegistration } from "./interfaces";
4 import { isDescriptor, ActivationType, ServiceMap, isDependencyRegistration, isValueRegistration, ServiceRegistration, DependencyRegistration } from "./interfaces";
5 5 import { AggregateDescriptor } from "./AggregateDescriptor";
6 import { isPrimitive } from "../safe";
6 import { isPrimitive, pmap } from "../safe";
7 7 import { ReferenceDescriptor } from "./ReferenceDescriptor";
8 8 import { ServiceDescriptor, ServiceDescriptorParams } from "./ServiceDescriptor";
9 9 import { ModuleResolverBase } from "./ModuleResolverBase";
10 10 import format = require("../text/format");
11 import { throws } from "assert";
11 12
12 13 export class Container {
13 14 _services: ServiceMap;
14 15
15 16 _cache: object;
16 17
17 18 _cleanup: (() => void)[];
18 19
19 20 _root: Container;
20 21
21 22 _parent: Container;
22 23
23 24 _resolver: ModuleResolverBase;
24 25
25 26 constructor(parent?: Container) {
26 27 this._parent = parent;
27 28 this._services = parent ? Object.create(parent._services) : {};
28 29 this._cache = {};
29 30 this._cleanup = [];
30 31 this._root = parent ? parent.getRootContainer() : this;
31 32 this._services.container = new ValueDescriptor(this);
32 33 }
33 34
34 35 getRootContainer() {
35 36 return this._root;
36 37 }
37 38
38 39 getParent() {
39 40 return this._parent;
40 41 }
41 42
42 getService(name: string, def?) {
43 resolve(name: string, def?) {
43 44 const d = this._services[name];
44 if (!d)
45 if (d === undefined) {
45 46 if (arguments.length > 1)
46 47 return def;
47 48 else
48 49 throw new Error("Service '" + name + "' isn't found");
49
50 if (!isDescriptor(d))
51 return d;
52
53 if (d.isInstanceCreated())
54 return d.getInstance();
50 }
55 51
56 52 const context = new ActivationContext(this, this._services);
57
58 53 try {
59 return d.activate(context, name);
54 return context.activate(d, name);
60 55 } catch (error) {
61 56 throw new ActivationError(name, context.getStack(), error);
62 57 }
63 58 }
64 59
60 getService(name: string, def?) {
61 return this.resolve.apply(this, arguments);
62 }
63
65 64 register(nameOrCollection, service?) {
66 65 if (arguments.length === 1) {
67 66 const data = nameOrCollection;
68 67 for (const name in data)
69 68 this.register(name, data[name]);
70 69 } else {
70 if (!isDescriptor(service))
71 throw new Error("The service parameter must be a descriptor");
72
71 73 this._services[nameOrCollection] = service;
72 74 }
73 75 return this;
74 76 }
75 77
76 78 onDispose(callback) {
77 79 if (!(callback instanceof Function))
78 80 throw new Error("The callback must be a function");
79 81 this._cleanup.push(callback);
80 82 }
81 83
82 84 dispose() {
83 85 if (this._cleanup) {
84 86 for (const f of this._cleanup)
85 87 f();
86 88 this._cleanup = null;
87 89 }
88 90 }
89 91
90 92 /**
91 93 * @param{String|Object} config
92 94 * The configuration of the contaier. Can be either a string or an object,
93 95 * if the configuration is an object it's treated as a collection of
94 96 * services which will be registed in the contaier.
95 97 *
96 98 * @param{Function} opts.contextRequire
97 99 * The function which will be used to load a configuration or types for services.
98 100 *
99 101 */
100 102 async configure(config: string | object, opts?: object) {
101 103 if (typeof (config) === "string") {
102 104 const resolver = await this._resolver.createResolver(config, opts);
103 105 const data = await this._resolver.loadModule(config);
104 106 return this._configure(data, { resolver });
105 107 } else {
106 108 return this._configure(config);
107 109 }
108 110 }
109 111
110 112 createChildContainer() {
111 113 return new Container(this);
112 114 }
113 115
114 116 has(id) {
115 117 return id in this._cache;
116 118 }
117 119
118 120 get(id) {
119 121 return this._cache[id];
120 122 }
121 123
122 124 store(id, value) {
123 125 return (this._cache[id] = value);
124 126 }
125 127
126 128 async _configure(data: object, opts?: { resolver: ModuleResolverBase }) {
127 129 const resolver = (opts && opts.resolver) || this._resolver;
128 130
129 const services: ServiceMap = {};
130
131 resolver.beginBatch();
132
133 async function parse(k) {
134 services[k] = await this._parse(data[k], resolver);
135 }
136
137 const batch = Object.keys(data).map(parse);
138
139 resolver.completeBatch();
140
141 await Promise.all(batch);
131 const services = await this._parseRegistrations(data, resolver);
142 132
143 133 this.register(services);
144 134 }
145 135
146 136 async _parse(registration: any, resolver: ModuleResolverBase) {
147 137 if (isPrimitive(registration) || isDescriptor(registration))
148 138 return registration;
149 139
150 140 if (isDependencyRegistration(registration)) {
151
152 return new ReferenceDescriptor({
153 name: registration.$dependency,
154 lazy: registration.lazy,
155 optional: registration.optional,
156 default: registration.default,
157 services: registration.services && this._parseObject(registration.services, resolver)
158 });
159
141 return this._paseReference(registration, resolver);
160 142 } else if (isValueRegistration(registration)) {
161
162 143 return !registration.parse ?
163 144 new ValueDescriptor(registration.$value) :
164 145 new AggregateDescriptor(this._parse(registration.$value, resolver));
165 146
166 147 } else if (registration.$type || registration.$factory) {
167 148 return this._parseService(registration, resolver);
168 149 } else if (registration instanceof Array) {
169 150 return this._parseArray(registration, resolver);
170 151 }
171 152
172 153 return this._parseObject(registration, resolver);
173 154 }
174 155
156 async _paseReference(registration: DependencyRegistration, resolver: ModuleResolverBase) {
157 return new ReferenceDescriptor({
158 name: registration.$dependency,
159 lazy: registration.lazy,
160 optional: registration.optional,
161 default: registration.default,
162 services: registration.services && await this._parseRegistrations(registration.services, resolver)
163 });
164 }
165
175 166 async _parseService(data: ServiceRegistration, resolver: ModuleResolverBase) {
176 167 const opts: ServiceDescriptorParams = {
177 168 owner: this
178 169 };
179 170
180 171 if (data.$type) {
181 172 if (data.$type instanceof Function)
182 173 opts.type = data.$type;
183 174 else if (typeof data.$type === "string")
184 175 opts.type = await resolver.resolve(data.$type);
185 176 else
186 177 throw new Error(format("Unsupported type specification: {0:json}", data.$type));
187 178 } else {
188 179 if (data.$factory instanceof Function)
189 180 opts.factory = data.$factory;
190 181 else if (typeof data.$factory === "string")
191 182 opts.factory = await resolver.resolve(data.$factory);
192 183 else
193 184 throw new Error(format("Unsupported factory specification: {0:json}", data.$factory));
194 185 }
195 186
196 187 if (data.services)
197 opts.services = await this._parseObject(data.services, resolver);
188 opts.services = await this._parseRegistrations(data.services, resolver);
198 189
199 if (data.inject instanceof Array)
200 opts.inject = await Promise.all(data.inject.map(x => this._parseObject(x, resolver)));
201 else
202 opts.inject = [await this._parseObject(data.inject, resolver)];
190 if (data.inject) {
191 if (data.inject instanceof Array)
192 opts.inject = await Promise.all(data.inject.map(x => this._parseObject(x, resolver)));
193 else
194 opts.inject = [await this._parseObject(data.inject, resolver)];
195 }
203 196
204 197 if (data.params)
205 198 opts.params = this._parse(data.params, resolver);
206 199
207 200 if (data.activation) {
208 201 if (typeof (data.activation) === "string") {
209 202 switch (data.activation.toLowerCase()) {
210 203 case "singleton":
211 204 opts.activation = ActivationType.Singleton;
212 205 break;
213 206 case "container":
214 207 opts.activation = ActivationType.Container;
215 208 break;
216 209 case "hierarchy":
217 210 opts.activation = ActivationType.Hierarchy;
218 211 break;
219 212 case "context":
220 213 opts.activation = ActivationType.Context;
221 214 break;
222 215 case "call":
223 216 opts.activation = ActivationType.Call;
224 217 break;
225 218 default:
226 219 throw new Error("Unknown activation type: " +
227 220 data.activation);
228 221 }
229 222 } else {
230 223 opts.activation = Number(data.activation);
231 224 }
232 225 }
233 226
234 227 if (data.cleanup)
235 228 opts.cleanup = data.cleanup;
236 229
237 230 return new ServiceDescriptor(opts);
238 231 }
239 232
240 _parseObject(data: object, resolver: ModuleResolverBase) {
233 async _parseObject(data: object, resolver: ModuleResolverBase) {
241 234 if (data.constructor &&
242 235 data.constructor.prototype !== Object.prototype)
243 236 return new ValueDescriptor(data);
244 237
245 238 const o = {};
246 239
247 240 for (const p in data)
248 o[p] = this._parse(data[p], resolver);
241 o[p] = await this._parse(data[p], resolver);
242
243 // TODO: handle inline descriptors properly
244 // const ex = {
245 // activate(ctx) {
246 // const value = ctx.activate(this.prop, "prop");
247 // // some code
248 // },
249
250 // // will be turned to ReferenceDescriptor
251 // prop: { $dependency: "depName" }
252 // };
249 253
250 254 return o;
251 255 }
252 256
253 _parseArray(data: Array<any>, resolver: ModuleResolverBase) {
257 async _parseArray(data: Array<any>, resolver: ModuleResolverBase) {
254 258 if (data.constructor &&
255 259 data.constructor.prototype !== Array.prototype)
256 260 return new ValueDescriptor(data);
257 261
258 return data.map(x => this._parse(x, resolver));
262 return pmap(data, x => this._parse(x, resolver));
263 }
264
265 async _parseRegistrations(data: object, resolver: ModuleResolverBase) {
266 if (data.constructor &&
267 data.constructor.prototype !== Object.prototype)
268 throw new Error("Registrations must be a simple object");
269
270 const o: ServiceMap = {};
271
272 for (const p of Object.keys(data)) {
273 const v = await this._parse(data[p], resolver);
274 o[p] = isDescriptor(v) ? v : new AggregateDescriptor(v);
275 }
276
277 return o;
259 278 }
260 279 }
@@ -1,114 +1,100
1 1 import { isNull, argumentNotEmptyString, each } from "../safe";
2 2 import { ActivationContext } from "./ActivationContext";
3 3 import { ServiceMap, Descriptor } from "./interfaces";
4 4 import { ActivationError } from "./ActivationError";
5 5
6 6 export interface ReferenceDescriptorParams {
7 7 name: string;
8 8 lazy?: boolean;
9 9 optional?: boolean;
10 10 default?;
11 11 services?: ServiceMap;
12 12 }
13 13
14 14 export class ReferenceDescriptor implements Descriptor {
15 15 _name: string;
16 16
17 17 _lazy = false;
18 18
19 19 _optional = false;
20 20
21 21 _default: any;
22 22
23 23 _services: ServiceMap;
24 24
25 25 constructor(opts: ReferenceDescriptorParams) {
26 26 argumentNotEmptyString(opts && opts.name, "opts.name");
27 27 this._name = opts.name;
28 28 this._lazy = !!opts.lazy;
29 29 this._optional = !!opts.optional;
30 this._default = !!opts.default;
30 this._default = opts.default;
31 31 this._services = opts.services;
32 32 }
33 33
34 34 activate(context: ActivationContext, name: string) {
35 // добавляем сервисы
36 if (this._services) {
37 for (const p of Object.keys(this._services))
38 context.register(p, this._services[p]);
39 }
35 40
36 41 if (this._lazy) {
37 // сохраняем контекст активации
38 context = context.clone();
39
40 // добавляем сервисы
41 if (this._services) {
42 for (const p of Object.keys(this._services))
43 context.register(p, this._services[p]);
44 }
42 const saved = context.clone();
45 43
46 44 return (cfg: ServiceMap) => {
47 45 // защищаем контекст на случай исключения в процессе
48 46 // активации
49 const ct = context.clone();
47 const ct = saved.clone();
50 48 try {
51 49 if (cfg) {
52 50 for (const k in cfg)
53 51 ct.register(k, cfg[k]);
54 52 }
55 53
56 return this._optional ? ct.getService(this._name, this._default) : ct
57 .getService(this._name);
54 return this._optional ? ct.resolve(this._name, this._default) : ct
55 .resolve(this._name);
58 56 } catch (error) {
59 57 throw new ActivationError(this._name, ct.getStack(), error);
60 58 }
61 59 };
62 60 } else {
63 context.enter(name, this, !!this._services);
64
65 61 // добавляем сервисы
66 62 if (this._services) {
67 63 for (const p of Object.keys(this._services))
68 64 context.register(p, this._services[p]);
69 65 }
70 66
71 67 const v = this._optional ?
72 context.getService(this._name, this._default) :
73 context.getService(this._name);
74
75 context.leave();
68 context.resolve(this._name, this._default) :
69 context.resolve(this._name);
76 70
77 71 return v;
78 72 }
79 73 }
80 74
81 isInstanceCreated() {
82 return false;
83 }
84
85 getInstance() {
86 throw new Error("The reference descriptor doesn't allowed to hold an instance");
87 }
88
89 75 toString() {
90 76 const opts = [];
91 77 if (this._optional)
92 78 opts.push("optional");
93 79 if (this._lazy)
94 80 opts.push("lazy");
95 81
96 82 const parts = [
97 83 "@ref "
98 84 ];
99 85 if (opts.length) {
100 86 parts.push("{");
101 87 parts.push(opts.join());
102 88 parts.push("} ");
103 89 }
104 90
105 91 parts.push(this._name);
106 92
107 93 if (!isNull(this._default)) {
108 94 parts.push(" = ");
109 95 parts.push(this._default);
110 96 }
111 97
112 98 return parts.join("");
113 99 }
114 100 }
@@ -1,273 +1,286
1 1 import { ActivationContext } from "./ActivationContext";
2 import { Descriptor, ActivationType, ServiceMap } from "./interfaces";
2 import { Descriptor, ActivationType, ServiceMap, isDescriptor } from "./interfaces";
3 3 import { Container } from "./Container";
4 4 import { argumentNotNull, isPrimitive, oid, isPromise } from "../safe";
5 5 import { Constructor, Factory } from "../interfaces";
6 import { TraceSource } from "../log/TraceSource";
6 7
7 8 let cacheId = 0;
8 9
10 const trace = TraceSource.get("@implab/core/di/ActivationContext");
11
9 12 function injectMethod(target, method, context, args) {
10 13 const m = target[method];
11 14 if (!m)
12 15 throw new Error("Method '" + method + "' not found");
13 16
14 17 if (args instanceof Array)
15 18 return m.apply(target, context.parse(args, "." + method));
16 19 else
17 20 return m.call(target, context.parse(args, "." + method));
18 21 }
19 22
20 23 function makeClenupCallback(target, method: ((instance) => void) | string) {
21 24 if (typeof (method) === "string") {
22 25 return () => {
23 26 target[method]();
24 27 };
25 28 } else {
26 29 return () => {
27 30 method(target);
28 31 };
29 32 }
30 33 }
31 34
35 // TODO: make async
36 function _parse(value, context: ActivationContext, path: string) {
37 if (isPrimitive(value))
38 return value;
39
40 if (isDescriptor(value))
41 return context.activate(value, path);
42
43 if (value instanceof Array)
44 return value.map((x, i) => this._parse(x, context, `${path}[${i}]`));
45
46 const t = {};
47 for (const p of Object.keys(value))
48 t[p] = this._parse(value[p], context, `${path}.${p}`);
49 return t;
50
51 }
52
32 53 export interface ServiceDescriptorParams {
33 54 activation?: ActivationType;
34 55
35 56 owner: Container;
36 57
37 58 type?: Constructor;
38 59
39 60 factory?: Factory;
40 61
41 62 params?;
42 63
43 64 inject?: object[];
44 65
45 66 services?: ServiceMap;
46 67
47 68 cleanup?: ((x) => void) | string;
48 69 }
49 70
50 71 export class ServiceDescriptor implements Descriptor {
51 72 _instance;
52 73
53 74 _hasInstance = false;
54 75
55 76 _activationType = ActivationType.Call;
56 77
57 78 _services: ServiceMap;
58 79
59 80 _type: Constructor = null;
60 81
61 82 _factory: Factory = null;
62 83
63 84 _params;
64 85
65 86 _inject: object[];
66 87
67 88 _cleanup: ((x) => void) | string;
68 89
69 90 _cacheId: any;
70 91
71 92 _owner: Container;
72 93
73 94 constructor(opts: ServiceDescriptorParams) {
74 95 argumentNotNull(opts, "opts");
75 96 argumentNotNull(opts.owner, "owner");
76 97
77 98 this._owner = opts.owner;
78 99
79 100 if (!(opts.type || opts.factory))
80 101 throw new Error(
81 102 "Either a type or a factory must be specified");
82 103
83 104 if (opts.activation)
84 105 this._activationType = opts.activation;
85 106
86 107 if (opts.type)
87 108 this._type = opts.type;
88 109
89 110 if (opts.params)
90 111 this._params = opts.params;
91 112
92 113 if (opts.inject)
93 114 this._inject = opts.inject;
94 115
95 116 if (opts.services)
96 117 this._services = opts.services;
97 118
98 119 if (opts.factory)
99 120 this._factory = opts.factory;
100 121
101 122 if (opts.cleanup) {
102 123 if (!(typeof (opts.cleanup) === "string" || opts.cleanup instanceof Function))
103 124 throw new Error(
104 125 "The cleanup parameter must be either a function or a function name");
105 126
106 127 this._cleanup = opts.cleanup;
107 128 }
108 129
109 130 if (this._activationType === ActivationType.Singleton) {
110 131 const tof = this._type || this._factory;
111 132
112 133 // create the persistent cache identifier for the type
113 134 if (isPrimitive(tof))
114 135 this._cacheId = tof;
115 136 else
116 137 this._cacheId = oid(tof);
117 138 } else {
118 139 this._cacheId = ++cacheId;
119 140 }
120 141 }
121 142
122 activate(context: ActivationContext, name: string) {
143 activate(context: ActivationContext) {
123 144 // if we have a local service records, register them first
124 145 let instance;
125 146
126 147 switch (this._activationType) {
127 148 case ActivationType.Singleton: // SINGLETON
128 149 // if the value is cached return it
129 150 if (this._hasInstance)
130 151 return this._instance;
131 152
132 153 // singletons are bound to the root container
133 154 const container = context.container.getRootContainer();
134 155
135 156 if (container.has(this._cacheId)) {
136 157 instance = container.get(this._cacheId);
137 158 } else {
138 instance = this._create(context, name);
159 instance = this._create(context);
139 160 container.store(this._cacheId, instance);
140 161 if (this._cleanup)
141 162 container.onDispose(
142 163 makeClenupCallback(instance, this._cleanup));
143 164 }
144 165
145 166 this._hasInstance = true;
146 167 return (this._instance = instance);
147 168
148 169 case ActivationType.Container: // CONTAINER
149 170 // return a cached value
150 171
151 172 if (this._hasInstance)
152 173 return this._instance;
153 174
154 175 // create an instance
155 instance = this._create(context, name);
176 instance = this._create(context);
156 177
157 178 // the instance is bound to the container
158 179 if (this._cleanup)
159 180 this._owner.onDispose(
160 181 makeClenupCallback(instance, this._cleanup));
161 182
162 183 // cache and return the instance
163 184 this._hasInstance = true;
164 185 return (this._instance = instance);
165 186 case ActivationType.Context: // CONTEXT
166 187 // return a cached value if one exists
167 188
168 189 if (context.has(this._cacheId))
169 190 return context.get(this._cacheId);
170 191 // context context activated instances are controlled by callers
171 return context.store(this._cacheId, this._create(
172 context,
173 name));
192 return context.store(this._cacheId, this._create(context));
174 193 case ActivationType.Call: // CALL
175 194 // per-call created instances are controlled by callers
176 return this._create(context, name);
195 return this._create(context);
177 196 case ActivationType.Hierarchy: // HIERARCHY
178 197 // hierarchy activated instances are behave much like container activated
179 198 // except they are created and bound to the child container
180 199
181 200 // return a cached value
182 201 if (context.container.has(this._cacheId))
183 202 return context.container.get(this._cacheId);
184 203
185 instance = this._create(context, name);
204 instance = this._create(context);
186 205
187 206 if (this._cleanup)
188 207 context.container.onDispose(makeClenupCallback(
189 208 instance,
190 209 this._cleanup));
191 210
192 211 return context.container.store(this._cacheId, instance);
193 212 default:
194 213 throw new Error("Invalid activation type: " + this._activationType);
195 214 }
196 215 }
197 216
198 217 isInstanceCreated() {
199 218 return this._hasInstance;
200 219 }
201 220
202 221 getInstance() {
203 222 return this._instance;
204 223 }
205 224
206 _create(context, name) {
207 context.enter(name, this, Boolean(this._services));
225 _create(context: ActivationContext) {
226 trace.debug(`constructing ${context._name}`);
208 227
209 228 if (this._activationType !== ActivationType.Call &&
210 229 context.visit(this._cacheId) > 0)
211 230 throw new Error("Recursion detected");
212 231
213 232 if (this._services) {
214 233 for (const p in this._services)
215 234 context.register(p, this._services[p]);
216 235 }
217 236
218 237 let instance;
219 238
220 239 if (!this._factory) {
221 240 const ctor = this._type;
222 241 if (this._params && this._params.length) {
223 242 this._factory = (...args) => {
224 243 const t = Object.create(ctor.prototype);
225 244 const inst = ctor.apply(t, args);
226 245 return isPrimitive(inst) ? t : inst;
227 246 };
228 247 } else {
229 248 this._factory = () => {
230 249 return new ctor();
231 250 };
232 251 }
233 252 }
234 253
235 254 if (this._params === undefined) {
236 255 instance = this._factory();
237 256 } else if (this._params instanceof Array) {
238 instance = this._factory.apply(this, context.parse(
239 this._params,
240 ".params"));
257 instance = this._factory.apply(this, _parse(this._params, context, "args"));
241 258 } else {
242 instance = this._factory(context.parse(
243 this._params,
244 ".params"));
259 instance = this._factory(_parse(this._params, context, "args"));
245 260 }
246 261
247 262 if (this._inject) {
248 263 this._inject.forEach(spec => {
249 264 for (const m in spec)
250 265 injectMethod(instance, m, context, spec[m]);
251 266 });
252 267 }
253 268
254 context.leave();
255
256 269 return instance;
257 270 }
258 271
259 272 // @constructor {singleton} foo/bar/Baz
260 273 // @factory {singleton}
261 274 toString() {
262 275 const parts = [];
263 276
264 277 parts.push(this._type ? "@constructor" : "@factory");
265 278
266 279 parts.push(ActivationType[this._activationType]);
267 280
268 281 if (typeof (this._type) === "string")
269 282 parts.push(this._type);
270 283
271 284 return parts.join(" ");
272 285 }
273 286 }
@@ -1,23 +1,17
1 1 import { Descriptor } from "./interfaces";
2 import { ActivationContext } from "./ActivationContext";
3 2
4 3 export class ValueDescriptor implements Descriptor {
5 4 _value;
6 5
7 6 constructor(value) {
8 7 this._value = value;
9 8 }
10 9
11 activate(context: ActivationContext, name: string) {
12 context.enter(name);
13 const v = this._value;
14 context.leave();
15 return v;
16 }
17 isInstanceCreated(): boolean {
18 return true;
19 }
20 getInstance() {
10 activate() {
21 11 return this._value;
22 12 }
13
14 toString() {
15 return `@type=${typeof this._value}`;
16 }
23 17 }
@@ -1,68 +1,66
1 1 import { isNull, isPrimitive } from "../safe";
2 2 import { ActivationContext } from "./ActivationContext";
3 3 import { Constructor, Factory } from "../interfaces";
4 4
5 5 export interface Descriptor {
6 6 activate(context: ActivationContext, name?: string);
7 isInstanceCreated(): boolean;
8 getInstance();
9 7 }
10 8
11 9 export function isDescriptor(x): x is Descriptor {
12 10 return (!isPrimitive(x)) &&
13 11 (x.activate instanceof Function);
14 12 }
15 13
16 14 export interface ServiceMap {
17 [s: string]: any;
15 [s: string]: Descriptor;
18 16 }
19 17
20 18 export enum ActivationType {
21 19 Singleton,
22 20 Container,
23 21 Hierarchy,
24 22 Context,
25 23 Call
26 24 }
27 25
28 26 export interface RegistrationWithServices {
29 27 services?: object;
30 28 }
31 29
32 30 export interface ServiceRegistration extends RegistrationWithServices {
33 31 $type?: string | Constructor;
34 32
35 33 $factory?: string | Factory;
36 34
37 35 activation?: "singleton" | "container" | "hierarchy" | "context" | "call";
38 36
39 37 params?;
40 38
41 39 inject?: object | object[];
42 40
43 41 cleanup: (instance) => void | string;
44 42 }
45 43
46 44 export interface ValueRegistration {
47 45 $value;
48 46 parse?: boolean;
49 47 }
50 48
51 49 export interface DependencyRegistration extends RegistrationWithServices {
52 50 $dependency: string;
53 51 lazy?: boolean;
54 52 optional?: boolean;
55 53 default?;
56 54 }
57 55
58 56 export function isServiceRegistration(x): x is ServiceRegistration {
59 57 return (!isPrimitive(x)) && ("$type" in x || "$factory" in x);
60 58 }
61 59
62 60 export function isValueRegistration(x): x is ValueRegistration {
63 61 return (!isPrimitive(x)) && ("$value" in x);
64 62 }
65 63
66 64 export function isDependencyRegistration(x): x is DependencyRegistration {
67 65 return (!isPrimitive(x)) && ("$depdendency" in x);
68 66 }
@@ -1,306 +1,306
1 1 let _nextOid = 0;
2 const _oid = Symbol("__oid");
2 const _oid = typeof Symbol === "function" ? Symbol("__oid") : "__oid";
3 3
4 4 export function oid(instance: object): string {
5 5 if (isNull(instance))
6 6 return null;
7 7
8 8 if (_oid in instance)
9 9 return instance[_oid];
10 10 else
11 11 return (instance[_oid] = "oid_" + (++_nextOid));
12 12 }
13 13
14 14 export function argumentNotNull(arg, name) {
15 15 if (arg === null || arg === undefined)
16 16 throw new Error("The argument " + name + " can't be null or undefined");
17 17 }
18 18
19 19 export function argumentNotEmptyString(arg, name) {
20 20 if (typeof (arg) !== "string" || !arg.length)
21 21 throw new Error("The argument '" + name + "' must be a not empty string");
22 22 }
23 23
24 24 export function argumentNotEmptyArray(arg, name) {
25 25 if (!(arg instanceof Array) || !arg.length)
26 26 throw new Error("The argument '" + name + "' must be a not empty array");
27 27 }
28 28
29 29 export function argumentOfType(arg, type, name) {
30 30 if (!(arg instanceof type))
31 31 throw new Error("The argument '" + name + "' type doesn't match");
32 32 }
33 33
34 34 export function isNull(arg) {
35 35 return (arg === null || arg === undefined);
36 36 }
37 37
38 38 export function isPrimitive(arg) {
39 39 return (arg === null || arg === undefined || typeof (arg) === "string" ||
40 40 typeof (arg) === "number" || typeof (arg) === "boolean");
41 41 }
42 42
43 43 export function isInteger(arg) {
44 44 return parseInt(arg, 10) === arg;
45 45 }
46 46
47 47 export function isNumber(arg) {
48 48 return parseFloat(arg) === arg;
49 49 }
50 50
51 51 export function isString(val) {
52 52 return typeof (val) === "string" || val instanceof String;
53 53 }
54 54
55 55 export function isPromise(val): val is PromiseLike<any> {
56 56 return "then" in val && val.then instanceof Function;
57 57 }
58 58
59 59 export function isNullOrEmptyString(str) {
60 60 if (str === null || str === undefined ||
61 61 ((typeof (str) === "string" || str instanceof String) && str.length === 0))
62 62 return true;
63 63 }
64 64
65 65 export function isNotEmptyArray(arg): arg is Array<any> {
66 66 return (arg instanceof Array && arg.length > 0);
67 67 }
68 68
69 69 export function getGlobal() {
70 70 return this;
71 71 }
72 72
73 73 export function get(member: string, context?: object) {
74 74 argumentNotEmptyString(member, "member");
75 75 let that = context || getGlobal();
76 76 const parts = member.split(".");
77 77 for (const m of parts) {
78 78 if (!m)
79 79 continue;
80 80 if (isNull(that = that[m]))
81 81 break;
82 82 }
83 83 return that;
84 84 }
85 85
86 86 /**
87 87 * Выполняет метод для каждого элемента массива, останавливается, когда
88 88 * либо достигнут конец массива, либо функция <c>cb</c> вернула
89 89 * значение.
90 90 *
91 91 * @param {Array | Object} obj массив элементов для просмотра
92 92 * @param {Function} cb функция, вызываемая для каждого элемента
93 93 * @param {Object} thisArg значение, которое будет передано в качестве
94 94 * <c>this</c> в <c>cb</c>.
95 95 * @returns Результат вызова функции <c>cb</c>, либо <c>undefined</c>
96 96 * если достигнут конец массива.
97 97 */
98 98 export function each(obj, cb, thisArg?) {
99 99 argumentNotNull(cb, "cb");
100 100 if (obj instanceof Array) {
101 101 for (let i = 0; i < obj.length; i++) {
102 102 const x = cb.call(thisArg, obj[i], i);
103 103 if (x !== undefined)
104 104 return x;
105 105 }
106 106 } else {
107 107 const keys = Object.keys(obj);
108 108 for (const k of keys) {
109 109 const x = cb.call(thisArg, obj[k], k);
110 110 if (x !== undefined)
111 111 return x;
112 112 }
113 113 }
114 114 }
115 115
116 116 /** Copies property values from a source object to the destination and returns
117 117 * the destination onject.
118 118 *
119 119 * @param dest The destination object into which properties from the source
120 120 * object will be copied.
121 121 * @param source The source of values which will be copied to the destination
122 122 * object.
123 123 * @param template An optional parameter specifies which properties should be
124 124 * copied from the source and how to map them to the destination. If the
125 125 * template is an array it contains the list of property names to copy from the
126 126 * source to the destination. In case of object the templates contains the map
127 127 * where keys are property names in the source and the values are property
128 128 * names in the destination object. If the template isn't specified then the
129 129 * own properties of the source are entirely copied to the destination.
130 130 *
131 131 */
132 132 export function mixin<T, S>(dest: T, source: S, template?: string[] | object): T & S {
133 133 argumentNotNull(dest, "to");
134 134 const _res = dest as T & S;
135 135
136 136 if (template instanceof Array) {
137 137 for (const p of template) {
138 138 if (p in source)
139 139 _res[p] = source[p];
140 140 }
141 141 } else if (template) {
142 142 const keys = Object.keys(source);
143 143 for (const p of keys) {
144 144 if (p in template)
145 145 _res[template[p]] = source[p];
146 146 }
147 147 } else {
148 148 const keys = Object.keys(source);
149 149 for (const p of keys)
150 150 _res[p] = source[p];
151 151 }
152 152
153 153 return _res;
154 154 }
155 155
156 156 /** Wraps the specified function to emulate an asynchronous execution.
157 157 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
158 158 * @param{Function|String} fn [Required] Function wich will be wrapped.
159 159 */
160 160 export function async(_fn: (...args: any[]) => any, thisArg): (...args: any[]) => PromiseLike<any> {
161 161 let fn = _fn;
162 162
163 163 if (arguments.length === 2 && !(fn instanceof Function))
164 164 fn = thisArg[fn];
165 165
166 166 if (fn == null)
167 167 throw new Error("The function must be specified");
168 168
169 169 function wrapresult(x, e?): PromiseLike<any> {
170 170 if (e) {
171 171 return {
172 172 then(cb, eb) {
173 173 try {
174 174 return eb ? wrapresult(eb(e)) : this;
175 175 } catch (e2) {
176 176 return wrapresult(null, e2);
177 177 }
178 178 }
179 179 };
180 180 } else {
181 181 if (x && x.then)
182 182 return x;
183 183 return {
184 184 then(cb) {
185 185 try {
186 186 return cb ? wrapresult(cb(x)) : this;
187 187 } catch (e2) {
188 188 return wrapresult(e2);
189 189 }
190 190 }
191 191 };
192 192 }
193 193 }
194 194
195 195 return (...args) => {
196 196 try {
197 197 return wrapresult(fn.apply(thisArg, args));
198 198 } catch (e) {
199 199 return wrapresult(null, e);
200 200 }
201 201 };
202 202 }
203 203
204 204 type _AnyFn = (...args) => any;
205 205
206 206 export function delegate<T, K extends keyof T>(target: T, _method: (K | _AnyFn)) {
207 207 let method;
208 208
209 209 if (!(_method instanceof Function)) {
210 210 argumentNotNull(target, "target");
211 211 method = target[_method];
212 212 if (!(method instanceof Function))
213 213 throw new Error("'method' argument must be a Function or a method name");
214 214 } else {
215 215 method = _method;
216 216 }
217 217
218 218 return (...args) => {
219 219 return method.apply(target, args);
220 220 };
221 221 }
222 222
223 223 /**
224 224 * Для каждого элемента массива вызывает указанную функцию и сохраняет
225 225 * возвращенное значение в массиве результатов.
226 226 *
227 227 * @remarks cb может выполняться асинхронно, при этом одновременно будет
228 228 * только одна операция.
229 229 *
230 230 * @async
231 231 */
232 232 export function pmap(items, cb) {
233 233 argumentNotNull(cb, "cb");
234 234
235 if (items && items.then instanceof Function)
235 if (isPromise(items))
236 236 return items.then(data => pmap(data, cb));
237 237
238 238 if (isNull(items) || !items.length)
239 239 return items;
240 240
241 241 let i = 0;
242 242 const result = [];
243 243
244 244 function next() {
245 245 let r;
246 246 let ri;
247 247
248 248 function chain(x) {
249 249 result[ri] = x;
250 250 return next();
251 251 }
252 252
253 253 while (i < items.length) {
254 254 r = cb(items[i], i);
255 255 ri = i;
256 256 i++;
257 257 if (isPromise(r)) {
258 258 return r.then(chain);
259 259 } else {
260 260 result[ri] = r;
261 261 }
262 262 }
263 263 return result;
264 264 }
265 265
266 266 return next();
267 267 }
268 268
269 269 /**
270 270 * Выбирает первый элемент из последовательности, или обещания, если в
271 271 * качестве параметра используется обещание, оно должно вернуть массив.
272 272 *
273 273 * @param {Function} cb обработчик результата, ему будет передан первый
274 274 * элемент последовательности в случае успеха
275 275 * @param {Function} err обработчик исключения, если массив пустой, либо
276 276 * не массив
277 277 *
278 278 * @remarks Если не указаны ни cb ни err, тогда функция вернет либо
279 279 * обещание, либо первый элемент.
280 280 * @async
281 281 */
282 282 export function first(sequence, cb: (x) => any, err: (x) => any) {
283 283 if (sequence) {
284 284 if (isPromise(sequence)) {
285 285 return sequence.then(res => first(res, cb, err));
286 286 } else if (sequence && "length" in sequence) {
287 287 if (sequence.length === 0) {
288 288 if (err)
289 289 return err(new Error("The sequence is empty"));
290 290 else
291 291 throw new Error("The sequence is empty");
292 292 }
293 293 return cb ? cb(sequence[0]) : sequence[0];
294 294 }
295 295 }
296 296
297 297 if (err)
298 298 return err(new Error("The sequence is required"));
299 299 else
300 300 throw new Error("The sequence is required");
301 301 }
302 302
303 303 export function destroy(d) {
304 304 if (d && "destroy" in d)
305 305 d.destroy();
306 306 }
@@ -1,26 +1,74
1 import { test } from "./TestTraits";
1 import { test, TapeWriter } from "./TestTraits";
2 2 import { Container } from "@implab/core/di/Container";
3 3 import { ReferenceDescriptor } from "@implab/core/di/ReferenceDescriptor";
4 4 import { AggregateDescriptor } from "@implab/core/di/AggregateDescriptor";
5 import { ValueDescriptor } from "@implab/core/di/ValueDescriptor";
6 import { TraceSource, DebugLevel } from "@implab/core/log/TraceSource";
7 import { Foo } from "./mock/Foo";
8 import { Bar } from "./mock/Bar";
9 import { isNull } from "@implab/core/safe";
5 10
6 test("Container register/getService tests", async t => {
11 test("Container register/resolve tests", async t => {
12 const writer = new TapeWriter(t);
13
14 TraceSource.on(ts => {
15 ts.level = DebugLevel;
16 writer.writeEvents(ts.events);
17 });
18
7 19 const container = new Container();
8 20
9 21 const connection1 = "db://localhost";
10 22
11 container.register("connection", connection1);
23 container.register("connection", new ValueDescriptor(connection1));
12 24
13 25 t.equals(container.getService("connection"), connection1);
14 26
15 27 container.register(
16 28 "dbParams",
17 29 new AggregateDescriptor({
18 30 timeout: 10,
19 connection: new ReferenceDescriptor({name: "connection"})
31 connection: new ReferenceDescriptor({ name: "connection" })
20 32 })
21 33 );
22 34
23 35 const dbParams = container.getService("dbParams");
24 t.equals(dbParams.connection, connection1);
36 t.equals(dbParams.connection, connection1, "should get connection");
37
38 writer.destroy();
39 });
40
41 test("Container configure/resolve tests", async t => {
42 const writer = new TapeWriter(t);
43
44 TraceSource.on(ts => {
45 ts.level = DebugLevel;
46 writer.writeEvents(ts.events);
47 });
48
49 const container = new Container();
50
51 await container.configure({
52 foo: {
53 $type: Foo
54 },
25 55
56 bar: {
57 $type: Bar,
58 params: {
59 db: {
60 provider: {
61 $dependency: "db"
62 }
63 }
64 }
65 }
66 });
67
68 const f1 = container.resolve("foo");
69 t.assert(!isNull(f1), "foo should be not null");
70
71 const b1 = container.resolve("bar");
72
73 writer.destroy();
26 74 });
@@ -1,75 +1,79
1 1 import { IObservable, ICancellation, IDestroyable } from "@implab/core/interfaces";
2 2 import { Cancellation } from "@implab/core/Cancellation";
3 3 import { TraceEvent, LogLevel, WarnLevel } from "@implab/core/log/TraceSource";
4 4 import * as tape from "tape";
5 5 import { argumentNotNull } from "@implab/core/safe";
6 6
7 7 export class TapeWriter implements IDestroyable {
8 8 readonly _tape: tape.Test;
9 9
10 10 _subscriptions = new Array<IDestroyable>();
11 11
12 12 constructor(t: tape.Test) {
13 13 argumentNotNull(t, "tape");
14 14 this._tape = t;
15 15 }
16 16
17 17 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
18 18 const subscription = source.on(this.writeEvent.bind(this));
19 19 if (ct.isSupported()) {
20 20 ct.register(subscription.destroy.bind(subscription));
21 21 }
22 22 this._subscriptions.push(subscription);
23 23 }
24 24
25 25 writeEvent(next: TraceEvent) {
26 26 if (next.level >= LogLevel) {
27 27 this._tape.comment("LOG " + next.arg);
28 28 } else if (next.level >= WarnLevel) {
29 29 this._tape.comment("WARN " + next.arg);
30 30 } else {
31 31 this._tape.comment("ERROR " + next.arg);
32 32 }
33 33 }
34 34
35 35 destroy() {
36 36 this._subscriptions.forEach(x => x.destroy());
37 37 }
38 38 }
39 39
40 40 export async function delay(timeout: number, ct: ICancellation = Cancellation.none) {
41 41 let un: IDestroyable;
42 42
43 43 try {
44 44 await new Promise((resolve, reject) => {
45 45 if (ct.isRequested()) {
46 46 un = ct.register(reject);
47 47 } else {
48 48 const ht = setTimeout(() => {
49 49 resolve();
50 50 }, timeout);
51 51
52 52 un = ct.register(e => {
53 53 clearTimeout(ht);
54 54 reject(e);
55 55 });
56 56 }
57 57 });
58 58 } finally {
59 59 if (un)
60 60 un.destroy();
61 61 }
62 62 }
63 63
64 64 export function test(name: string, cb: (t: tape.Test) => any) {
65 65 tape(name, async t => {
66 66 try {
67 67 await cb(t);
68 68 } catch (e) {
69
70 // verbose error information
71 // tslint:disable-next-line
69 72 console.error(e);
70 73 t.fail(e);
74
71 75 } finally {
72 76 t.end();
73 77 }
74 78 });
75 79 }
@@ -1,15 +1,17
1 1 {
2 2 "compilerOptions": {
3 3 "target": "es3",
4 4 "module": "amd",
5 5 "sourceMap": true,
6 6 "outDir" : "build/dist",
7 7 "declaration": true,
8 8 "lib": [
9 "es2015"
9 "es5",
10 "es2015.promise",
11 "es2015.symbol"
10 12 ]
11 13 },
12 14 "include" : [
13 15 "src/ts/**/*.ts"
14 16 ]
15 17 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now