##// END OF EJS Templates
tests, refactoring, fixes
cin -
r40:6559c5b81a19 di-typescript
parent child
Show More
@@ -0,0 +1,26
1 import { test } from "./TestTraits";
2 import { Container } from "@implab/core/di/Container";
3 import { ReferenceDescriptor } from "@implab/core/di/ReferenceDescriptor";
4 import { AggregateDescriptor } from "@implab/core/di/AggregateDescriptor";
5
6 test("Container register/getService tests", async t => {
7 const container = new Container();
8
9 const connection1 = "db://localhost";
10
11 container.register("connection", connection1);
12
13 t.equals(container.getService("connection"), connection1);
14
15 container.register(
16 "dbParams",
17 new AggregateDescriptor({
18 timeout: 10,
19 connection: new ReferenceDescriptor({name: "connection"})
20 })
21 );
22
23 const dbParams = container.getService("dbParams");
24 t.equals(dbParams.connection, connection1);
25
26 });
@@ -0,0 +1,43
1 import { IActivatable, ICancellation, IActivationController } from "@implab/core/interfaces";
2 import { Cancellation } from "@implab/core/Cancellation";
3
4 export class MockActivationController implements IActivationController {
5
6 _active: IActivatable = null;
7
8 getActive(): IActivatable {
9 return this._active;
10 }
11
12 async deactivate() {
13 if (this._active)
14 await this._active.deactivate();
15 this._active = null;
16 }
17
18 async activate(component: IActivatable) {
19 if (!component || component.isActive())
20 return;
21 component.setActivationController(this);
22
23 await component.activate();
24 }
25
26 async activating(component: IActivatable, ct: ICancellation = Cancellation.none) {
27 if (component !== this._active)
28 await this.deactivate();
29 }
30
31 async activated(component: IActivatable, ct: ICancellation = Cancellation.none) {
32 this._active = component;
33 }
34
35 async deactivating(component: IActivatable, ct: ICancellation = Cancellation.none) {
36
37 }
38
39 async deactivated(component: IActivatable, ct: ICancellation = Cancellation.none) {
40 if (this._active === component)
41 this._active = null;
42 }
43 }
@@ -0,0 +1,6
1 import { AsyncComponent } from "@implab/core/components/AsyncComponent";
2 import { ActivatableMixin } from "@implab/core/components/ActivatableMixin";
3
4 export class SimpleActivatable extends ActivatableMixin(AsyncComponent) {
5
6 }
@@ -1,94 +1,94
1 1 if (release != 'rtm') {
2 2 version += "-$release"
3 3 }
4 4
5 5 println "version: $version"
6 6
7 7 def distDir = "$buildDir/dist"
8 8 def testDir = "$buildDir/test"
9 9
10 10 task clean {
11 11 doLast {
12 12 delete buildDir
13 13 delete 'node_modules/@implab'
14 14 }
15 15 }
16 16
17 17 task cleanNpm {
18 18 doLast {
19 19 delete 'node_modules'
20 20 }
21 21 }
22 22
23 23 task _npmInstall() {
24 24 inputs.file("package.json")
25 25 outputs.dir("node_modules")
26 26 doLast {
27 27 exec {
28 28 commandLine 'npm', 'install'
29 29 }
30 30 }
31 31 }
32 32
33 33 task _legacyJs(type:Copy) {
34 34 from 'src/js/'
35 35 into distDir
36 36 }
37 37
38 38 task _buildTs(dependsOn: _npmInstall, type:Exec) {
39 39 inputs.dir('src/ts')
40 inputs.file('tsc.json')
40 inputs.file('tsconfig.json')
41 41 outputs.dir(distDir)
42 42
43 43 commandLine 'node_modules/.bin/tsc', '-p', 'tsconfig.json'
44 44 }
45 45
46 46 task _packageMeta(type: Copy) {
47 47 inputs.property("version", version)
48 48 from('.') {
49 49 include 'package.json', '.npmignore', 'readme.md', 'license', 'history.md'
50 50 }
51 51 into distDir
52 52 doLast {
53 53 exec {
54 54 workingDir distDir
55 55 commandLine 'npm', 'version', version
56 56 }
57 57 }
58 58 }
59 59
60 60 task build(dependsOn: [_legacyJs, _npmInstall, _buildTs, _packageMeta]) {
61 61
62 62 }
63 63
64 64 task _localInstall(dependsOn: build, type: Exec) {
65 65 inputs.file("$distDir/package.json")
66 66 outputs.upToDateWhen {
67 67 new File("$projectDir/node_modules/@implab/core").exists()
68 68 }
69 69
70 70 commandLine 'npm', 'install', '--no-save', '--force', distDir
71 71 }
72 72
73 73 task copyJsTests(type: Copy) {
74 74 from 'test/js'
75 75 into testDir
76 76 }
77 77
78 78 task buildTests(dependsOn: _localInstall, type: Exec) {
79 79 inputs.dir('test/ts')
80 inputs.file('tsc.test.json')
80 inputs.file('tsconfig.test.json')
81 81 outputs.dir(testDir)
82 82
83 83 commandLine 'node_modules/.bin/tsc', '-p', 'tsconfig.test.json'
84 84 }
85 85
86 86 task test(dependsOn: [copyJsTests, buildTests], type: Exec) {
87 87 commandLine 'node', 'run-amd-tests.js'
88 88 }
89 89
90 90 task pack(dependsOn: build, type: Exec) {
91 91 workingDir = distDir
92 92
93 93 commandLine 'npm', 'pack'
94 94 } No newline at end of file
@@ -1,2 +1,2
1 version=1.1.1
1 version=1.1.2
2 2 release=rtm No newline at end of file
@@ -1,445 +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 "version": "10.5.1",
9 "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.1.tgz",
10 "integrity": "sha512-AFLl1IALIuyt6oK4AYZsgWVJ/5rnyzQWud7IebaZWWV3YmgtPZkQmYio9R5Ze/2pdd7XfqF5bP+hWS11mAKoOQ==",
8 "version": "10.12.12",
9 "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.12.tgz",
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 "version": "1.0.1",
52 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
53 "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
51 "version": "0.1.2",
52 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.1.2.tgz",
53 "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=",
54 54 "dev": true
55 55 },
56 56 "define-properties": {
57 "version": "1.1.2",
58 "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
59 "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
57 "version": "1.1.3",
58 "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
59 "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
60 60 "dev": true,
61 61 "requires": {
62 "foreach": "^2.0.5",
63 "object-keys": "^1.0.8"
62 "object-keys": "^1.0.12"
63 },
64 "dependencies": {
65 "object-keys": {
66 "version": "1.0.12",
67 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
68 "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
69 "dev": true
70 }
64 71 }
65 72 },
66 73 "defined": {
67 "version": "1.0.0",
68 "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
69 "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
74 "version": "0.0.0",
75 "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz",
76 "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=",
70 77 "dev": true
71 78 },
72 79 "dojo": {
73 80 "version": "1.13.0",
74 81 "resolved": "https://registry.npmjs.org/dojo/-/dojo-1.13.0.tgz",
75 82 "integrity": "sha512-mGoGvsXAbPkUrBnxCoO7m6CFH8jvWq7rAL7fP7jrhJEOyswA/bZwWdXwEH0ovs68t8S0+xOpV/3V7addYbaiAA=="
76 83 },
77 84 "duplexer": {
78 85 "version": "0.1.1",
79 "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
86 "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
80 87 "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
81 88 "dev": true
82 89 },
83 90 "es-abstract": {
84 91 "version": "1.12.0",
85 92 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
86 93 "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==",
87 94 "dev": true,
88 95 "requires": {
89 96 "es-to-primitive": "^1.1.1",
90 97 "function-bind": "^1.1.1",
91 98 "has": "^1.0.1",
92 99 "is-callable": "^1.1.3",
93 100 "is-regex": "^1.0.4"
94 101 }
95 102 },
96 103 "es-to-primitive": {
97 "version": "1.1.1",
98 "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
99 "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
104 "version": "1.2.0",
105 "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
106 "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
100 107 "dev": true,
101 108 "requires": {
102 "is-callable": "^1.1.1",
109 "is-callable": "^1.1.4",
103 110 "is-date-object": "^1.0.1",
104 "is-symbol": "^1.0.1"
111 "is-symbol": "^1.0.2"
105 112 }
106 113 },
107 114 "faucet": {
108 115 "version": "0.0.1",
109 116 "resolved": "https://registry.npmjs.org/faucet/-/faucet-0.0.1.tgz",
110 117 "integrity": "sha1-WX3PHSGJosBiMhtZHo8VHtIDnZw=",
111 118 "dev": true,
112 119 "requires": {
113 120 "defined": "0.0.0",
114 121 "duplexer": "~0.1.1",
115 122 "minimist": "0.0.5",
116 123 "sprintf": "~0.1.3",
117 124 "tap-parser": "~0.4.0",
118 125 "tape": "~2.3.2",
119 126 "through2": "~0.2.3"
120 127 },
121 128 "dependencies": {
122 "deep-equal": {
123 "version": "0.1.2",
124 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.1.2.tgz",
125 "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=",
126 "dev": true
127 },
128 "defined": {
129 "version": "0.0.0",
130 "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz",
131 "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=",
132 "dev": true
133 },
134 "minimist": {
135 "version": "0.0.5",
136 "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz",
137 "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=",
138 "dev": true
139 },
140 129 "tape": {
141 130 "version": "2.3.3",
142 "resolved": "https://registry.npmjs.org/tape/-/tape-2.3.3.tgz",
131 "resolved": "http://registry.npmjs.org/tape/-/tape-2.3.3.tgz",
143 132 "integrity": "sha1-Lnzgox3wn41oUWZKcYQuDKUFevc=",
144 133 "dev": true,
145 134 "requires": {
146 135 "deep-equal": "~0.1.0",
147 136 "defined": "~0.0.0",
148 137 "inherits": "~2.0.1",
149 138 "jsonify": "~0.0.0",
150 139 "resumer": "~0.0.0",
151 140 "through": "~2.3.4"
152 141 }
153 142 }
154 143 }
155 144 },
156 145 "for-each": {
157 146 "version": "0.3.3",
158 147 "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
159 148 "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
160 149 "dev": true,
161 150 "requires": {
162 151 "is-callable": "^1.1.3"
163 152 }
164 153 },
165 "foreach": {
166 "version": "2.0.5",
167 "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
168 "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
169 "dev": true
170 },
171 154 "fs.realpath": {
172 155 "version": "1.0.0",
173 156 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
174 157 "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
175 158 "dev": true
176 159 },
177 160 "function-bind": {
178 161 "version": "1.1.1",
179 162 "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
180 163 "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
181 164 "dev": true
182 165 },
183 166 "glob": {
184 "version": "7.1.2",
185 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
186 "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
167 "version": "7.1.3",
168 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
169 "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
187 170 "dev": true,
188 171 "requires": {
189 172 "fs.realpath": "^1.0.0",
190 173 "inflight": "^1.0.4",
191 174 "inherits": "2",
192 175 "minimatch": "^3.0.4",
193 176 "once": "^1.3.0",
194 177 "path-is-absolute": "^1.0.0"
195 178 }
196 179 },
197 180 "has": {
198 181 "version": "1.0.3",
199 182 "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
200 183 "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
201 184 "dev": true,
202 185 "requires": {
203 186 "function-bind": "^1.1.1"
204 187 }
205 188 },
189 "has-symbols": {
190 "version": "1.0.0",
191 "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
192 "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
193 "dev": true
194 },
206 195 "inflight": {
207 196 "version": "1.0.6",
208 197 "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
209 198 "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
210 199 "dev": true,
211 200 "requires": {
212 201 "once": "^1.3.0",
213 202 "wrappy": "1"
214 203 }
215 204 },
216 205 "inherits": {
217 206 "version": "2.0.3",
218 207 "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
219 208 "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
220 209 "dev": true
221 210 },
222 211 "is-callable": {
223 "version": "1.1.3",
224 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",
225 "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=",
212 "version": "1.1.4",
213 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
214 "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
226 215 "dev": true
227 216 },
228 217 "is-date-object": {
229 218 "version": "1.0.1",
230 219 "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
231 220 "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
232 221 "dev": true
233 222 },
234 223 "is-regex": {
235 224 "version": "1.0.4",
236 225 "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
237 226 "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
238 227 "dev": true,
239 228 "requires": {
240 229 "has": "^1.0.1"
241 230 }
242 231 },
243 232 "is-symbol": {
244 "version": "1.0.1",
245 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
246 "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=",
247 "dev": true
233 "version": "1.0.2",
234 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
235 "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
236 "dev": true,
237 "requires": {
238 "has-symbols": "^1.0.0"
239 }
248 240 },
249 241 "isarray": {
250 242 "version": "0.0.1",
251 243 "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
252 244 "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
253 245 "dev": true
254 246 },
255 247 "jsonify": {
256 248 "version": "0.0.0",
257 249 "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
258 250 "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
259 251 "dev": true
260 252 },
261 253 "minimatch": {
262 254 "version": "3.0.4",
263 255 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
264 256 "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
265 257 "dev": true,
266 258 "requires": {
267 259 "brace-expansion": "^1.1.7"
268 260 }
269 261 },
270 262 "minimist": {
271 "version": "1.2.0",
272 "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
273 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
263 "version": "0.0.5",
264 "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz",
265 "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=",
274 266 "dev": true
275 267 },
276 268 "object-inspect": {
277 269 "version": "1.6.0",
278 270 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz",
279 271 "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==",
280 272 "dev": true
281 273 },
282 274 "object-keys": {
283 "version": "1.0.12",
284 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
285 "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
275 "version": "0.4.0",
276 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
277 "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
286 278 "dev": true
287 279 },
288 280 "once": {
289 281 "version": "1.4.0",
290 282 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
291 283 "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
292 284 "dev": true,
293 285 "requires": {
294 286 "wrappy": "1"
295 287 }
296 288 },
297 289 "path-is-absolute": {
298 290 "version": "1.0.1",
299 "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
291 "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
300 292 "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
301 293 "dev": true
302 294 },
303 295 "path-parse": {
304 "version": "1.0.5",
305 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
306 "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
296 "version": "1.0.6",
297 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
298 "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
307 299 "dev": true
308 300 },
309 301 "readable-stream": {
310 302 "version": "1.1.14",
311 "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
303 "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
312 304 "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
313 305 "dev": true,
314 306 "requires": {
315 307 "core-util-is": "~1.0.0",
316 308 "inherits": "~2.0.1",
317 309 "isarray": "0.0.1",
318 310 "string_decoder": "~0.10.x"
319 311 }
320 312 },
321 313 "requirejs": {
322 314 "version": "2.3.6",
323 315 "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
324 316 "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
325 317 "dev": true
326 318 },
327 319 "resolve": {
328 320 "version": "1.7.1",
329 321 "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
330 322 "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
331 323 "dev": true,
332 324 "requires": {
333 325 "path-parse": "^1.0.5"
334 326 }
335 327 },
336 328 "resumer": {
337 329 "version": "0.0.0",
338 330 "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz",
339 331 "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=",
340 332 "dev": true,
341 333 "requires": {
342 334 "through": "~2.3.4"
343 335 }
344 336 },
345 337 "sprintf": {
346 338 "version": "0.1.5",
347 339 "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz",
348 340 "integrity": "sha1-j4PjmpMXwaUCy324BQ5Rxnn27c8=",
349 341 "dev": true
350 342 },
351 343 "string.prototype.trim": {
352 344 "version": "1.1.2",
353 345 "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz",
354 346 "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=",
355 347 "dev": true,
356 348 "requires": {
357 349 "define-properties": "^1.1.2",
358 350 "es-abstract": "^1.5.0",
359 351 "function-bind": "^1.0.2"
360 352 }
361 353 },
362 354 "string_decoder": {
363 355 "version": "0.10.31",
364 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
356 "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
365 357 "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
366 358 "dev": true
367 359 },
368 360 "tap-parser": {
369 361 "version": "0.4.3",
370 362 "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-0.4.3.tgz",
371 363 "integrity": "sha1-pOrhkMENdsehEZIf84u+TVjwnuo=",
372 364 "dev": true,
373 365 "requires": {
374 366 "inherits": "~2.0.1",
375 367 "readable-stream": "~1.1.11"
376 368 }
377 369 },
378 370 "tape": {
379 371 "version": "4.9.1",
380 372 "resolved": "https://registry.npmjs.org/tape/-/tape-4.9.1.tgz",
381 373 "integrity": "sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw==",
382 374 "dev": true,
383 375 "requires": {
384 376 "deep-equal": "~1.0.1",
385 377 "defined": "~1.0.0",
386 378 "for-each": "~0.3.3",
387 379 "function-bind": "~1.1.1",
388 380 "glob": "~7.1.2",
389 381 "has": "~1.0.3",
390 382 "inherits": "~2.0.3",
391 383 "minimist": "~1.2.0",
392 384 "object-inspect": "~1.6.0",
393 385 "resolve": "~1.7.1",
394 386 "resumer": "~0.0.0",
395 387 "string.prototype.trim": "~1.1.2",
396 388 "through": "~2.3.8"
389 },
390 "dependencies": {
391 "deep-equal": {
392 "version": "1.0.1",
393 "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
394 "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
395 "dev": true
396 },
397 "defined": {
398 "version": "1.0.0",
399 "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
400 "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
401 "dev": true
402 },
403 "minimist": {
404 "version": "1.2.0",
405 "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
406 "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
407 "dev": true
408 }
397 409 }
398 410 },
399 411 "through": {
400 412 "version": "2.3.8",
401 "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
413 "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
402 414 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
403 415 "dev": true
404 416 },
405 417 "through2": {
406 418 "version": "0.2.3",
407 "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
419 "resolved": "http://registry.npmjs.org/through2/-/through2-0.2.3.tgz",
408 420 "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=",
409 421 "dev": true,
410 422 "requires": {
411 423 "readable-stream": "~1.1.9",
412 424 "xtend": "~2.1.1"
413 425 }
414 426 },
415 427 "typescript": {
416 "version": "3.1.6",
417 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz",
418 "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==",
428 "version": "3.2.1",
429 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.1.tgz",
430 "integrity": "sha512-jw7P2z/h6aPT4AENXDGjcfHTu5CSqzsbZc6YlUIebTyBAq8XaKp78x7VcSh30xwSCcsu5irZkYZUSFP1MrAMbg==",
419 431 "dev": true
420 432 },
421 433 "wrappy": {
422 434 "version": "1.0.2",
423 435 "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
424 436 "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
425 437 "dev": true
426 438 },
427 439 "xtend": {
428 440 "version": "2.1.2",
429 441 "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
430 442 "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
431 443 "dev": true,
432 444 "requires": {
433 445 "object-keys": "~0.4.0"
434 },
435 "dependencies": {
436 "object-keys": {
437 "version": "0.4.0",
438 "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
439 "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
440 "dev": true
441 446 }
442 447 }
443 448 }
444 449 }
445 }
@@ -1,134 +1,134
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 11 service: Descriptor;
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 25 container: Container;
26 26
27 27 constructor(container: Container, services: ServiceMap, cache?: object, visited?) {
28 28 argumentNotNull(container, "container");
29 29 argumentNotNull(services, "services");
30 30
31 31 this._visited = visited || {};
32 32 this._stack = [];
33 33 this._cache = cache || {};
34 34 this._services = services;
35 35 this.container = container;
36 36 }
37 37
38 38 getService(name, def?): any {
39 39 const d = this._services[name];
40 40
41 41 if (!d)
42 42 if (arguments.length > 1)
43 43 return def;
44 44 else
45 45 throw new Error(`Service ${name} not found`);
46 46
47 return d.activate(this, name);
47 return isDescriptor(d) ? d.activate(this, name) : d;
48 48 }
49 49
50 50 /**
51 51 * registers services local to the the activation context
52 52 *
53 53 * @name{string} the name of the service
54 54 * @service{string} the service descriptor to register
55 55 */
56 56 register(name: string, service: Descriptor) {
57 57 argumentNotEmptyString(name, "name");
58 58
59 59 this._services[name] = service;
60 60 }
61 61
62 62 clone() {
63 63 return new ActivationContext(
64 64 this.container,
65 65 Object.create(this._services),
66 66 this._cache,
67 67 this._visited
68 68 );
69 69 }
70 70
71 71 has(id: string) {
72 72 return id in this._cache;
73 73 }
74 74
75 75 get(id: string) {
76 76 return this._cache[id];
77 77 }
78 78
79 79 store(id: string, value) {
80 80 return (this._cache[id] = value);
81 81 }
82 82
83 parse(data: object, name: string) {
83 parse(data, name: string) {
84 84 if (isPrimitive(data))
85 85 return data;
86 86
87 87 if (isDescriptor(data)) {
88 88 return data.activate(this, name);
89 89 } else if (data instanceof Array) {
90 90 this.enter(name);
91 91 const v = data.map( (x, i) => this.parse(x, `[${i}]`));
92 92 this.leave();
93 93 return v;
94 94 } else {
95 95 this.enter(name);
96 96 const result = {};
97 97 for (const p in data)
98 98 result[p] = this.parse(data[p], "." + p);
99 99 this.leave();
100 100 return result;
101 101 }
102 102 }
103 103
104 104 visit(id: string) {
105 105 const count = this._visited[id] || 0;
106 106 this._visited[id] = count + 1;
107 107 return count;
108 108 }
109 109
110 110 getStack() {
111 111 return this._stack.slice().reverse();
112 112 }
113 113
114 114 enter(name: string, d?: Descriptor, localize?: boolean) {
115 115 if (trace.isLogEnabled())
116 116 trace.log("enter " + name + " " + (d || "") +
117 117 (localize ? " localize" : ""));
118 118 this._stack.push({
119 119 name,
120 120 service: d,
121 121 scope: this._services
122 122 });
123 123 if (localize)
124 124 this._services = Object.create(this._services);
125 125 }
126 126
127 127 leave() {
128 128 const ctx = this._stack.pop();
129 129 this._services = ctx.scope;
130 130
131 131 if (trace.isLogEnabled())
132 132 trace.log("leave " + ctx.name + " " + (ctx.service || ""));
133 133 }
134 134 }
@@ -1,259 +1,260
1 1 import { ActivationContext } from "./ActivationContext";
2 2 import { ValueDescriptor } from "./ValueDescriptor";
3 3 import { ActivationError } from "./ActivationError";
4 4 import { isDescriptor, ActivationType, ServiceMap, isDependencyRegistration, isValueRegistration, ServiceRegistration } from "./interfaces";
5 5 import { AggregateDescriptor } from "./AggregateDescriptor";
6 6 import { isPrimitive } 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 11
12 12 export class Container {
13 13 _services: ServiceMap;
14 14
15 15 _cache: object;
16 16
17 17 _cleanup: (() => void)[];
18 18
19 19 _root: Container;
20 20
21 21 _parent: Container;
22 22
23 23 _resolver: ModuleResolverBase;
24 24
25 25 constructor(parent?: Container) {
26 26 this._parent = parent;
27 27 this._services = parent ? Object.create(parent._services) : {};
28 28 this._cache = {};
29 29 this._cleanup = [];
30 30 this._root = parent ? parent.getRootContainer() : this;
31 31 this._services.container = new ValueDescriptor(this);
32 32 }
33 33
34 34 getRootContainer() {
35 35 return this._root;
36 36 }
37 37
38 38 getParent() {
39 39 return this._parent;
40 40 }
41 41
42 getService<T = any>(name: string, def?: T) {
42 getService(name: string, def?) {
43 43 const d = this._services[name];
44 44 if (!d)
45 45 if (arguments.length > 1)
46 46 return def;
47 47 else
48 48 throw new Error("Service '" + name + "' isn't found");
49 49
50 if (!isDescriptor(d))
51 return d;
52
50 53 if (d.isInstanceCreated())
51 return d.getInstance() as T;
54 return d.getInstance();
52 55
53 56 const context = new ActivationContext(this, this._services);
54 57
55 58 try {
56 return d.activate(context, name) as T;
59 return d.activate(context, name);
57 60 } catch (error) {
58 61 throw new ActivationError(name, context.getStack(), error);
59 62 }
60 63 }
61 64
62 65 register(nameOrCollection, service?) {
63 66 if (arguments.length === 1) {
64 67 const data = nameOrCollection;
65 68 for (const name in data)
66 69 this.register(name, data[name]);
67 70 } else {
68 if (!(isDescriptor(service)))
69 service = new ValueDescriptor(service);
70 71 this._services[nameOrCollection] = service;
71 72 }
72 73 return this;
73 74 }
74 75
75 76 onDispose(callback) {
76 77 if (!(callback instanceof Function))
77 78 throw new Error("The callback must be a function");
78 79 this._cleanup.push(callback);
79 80 }
80 81
81 82 dispose() {
82 83 if (this._cleanup) {
83 84 for (const f of this._cleanup)
84 85 f();
85 86 this._cleanup = null;
86 87 }
87 88 }
88 89
89 90 /**
90 91 * @param{String|Object} config
91 92 * The configuration of the contaier. Can be either a string or an object,
92 93 * if the configuration is an object it's treated as a collection of
93 94 * services which will be registed in the contaier.
94 95 *
95 96 * @param{Function} opts.contextRequire
96 97 * The function which will be used to load a configuration or types for services.
97 98 *
98 99 */
99 100 async configure(config: string | object, opts?: object) {
100 101 if (typeof (config) === "string") {
101 102 const resolver = await this._resolver.createResolver(config, opts);
102 103 const data = await this._resolver.loadModule(config);
103 104 return this._configure(data, { resolver });
104 105 } else {
105 106 return this._configure(config);
106 107 }
107 108 }
108 109
109 110 createChildContainer() {
110 111 return new Container(this);
111 112 }
112 113
113 114 has(id) {
114 115 return id in this._cache;
115 116 }
116 117
117 118 get(id) {
118 119 return this._cache[id];
119 120 }
120 121
121 122 store(id, value) {
122 123 return (this._cache[id] = value);
123 124 }
124 125
125 126 async _configure(data: object, opts?: { resolver: ModuleResolverBase }) {
126 127 const resolver = (opts && opts.resolver) || this._resolver;
127 128
128 129 const services: ServiceMap = {};
129 130
130 131 resolver.beginBatch();
131 132
132 133 async function parse(k) {
133 134 services[k] = await this._parse(data[k], resolver);
134 135 }
135 136
136 137 const batch = Object.keys(data).map(parse);
137 138
138 139 resolver.completeBatch();
139 140
140 141 await Promise.all(batch);
141 142
142 143 this.register(services);
143 144 }
144 145
145 146 async _parse(registration: any, resolver: ModuleResolverBase) {
146 147 if (isPrimitive(registration) || isDescriptor(registration))
147 148 return registration;
148 149
149 150 if (isDependencyRegistration(registration)) {
150 151
151 return new ReferenceDescriptor(
152 registration.$dependency,
153 registration.lazy,
154 registration.optional,
155 registration["default"],
156 registration.services && this._parseObject(registration.services, resolver)
157 );
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 });
158 159
159 160 } else if (isValueRegistration(registration)) {
160 161
161 162 return !registration.parse ?
162 163 new ValueDescriptor(registration.$value) :
163 164 new AggregateDescriptor(this._parse(registration.$value, resolver));
164 165
165 166 } else if (registration.$type || registration.$factory) {
166 167 return this._parseService(registration, resolver);
167 168 } else if (registration instanceof Array) {
168 169 return this._parseArray(registration, resolver);
169 170 }
170 171
171 172 return this._parseObject(registration, resolver);
172 173 }
173 174
174 175 async _parseService(data: ServiceRegistration, resolver: ModuleResolverBase) {
175 176 const opts: ServiceDescriptorParams = {
176 177 owner: this
177 178 };
178 179
179 180 if (data.$type) {
180 181 if (data.$type instanceof Function)
181 182 opts.type = data.$type;
182 183 else if (typeof data.$type === "string")
183 184 opts.type = await resolver.resolve(data.$type);
184 185 else
185 186 throw new Error(format("Unsupported type specification: {0:json}", data.$type));
186 187 } else {
187 188 if (data.$factory instanceof Function)
188 189 opts.factory = data.$factory;
189 190 else if (typeof data.$factory === "string")
190 191 opts.factory = await resolver.resolve(data.$factory);
191 192 else
192 193 throw new Error(format("Unsupported factory specification: {0:json}", data.$factory));
193 194 }
194 195
195 196 if (data.services)
196 197 opts.services = await this._parseObject(data.services, resolver);
197 198
198 199 if (data.inject instanceof Array)
199 200 opts.inject = await Promise.all(data.inject.map(x => this._parseObject(x, resolver)));
200 201 else
201 202 opts.inject = [await this._parseObject(data.inject, resolver)];
202 203
203 204 if (data.params)
204 205 opts.params = this._parse(data.params, resolver);
205 206
206 207 if (data.activation) {
207 208 if (typeof (data.activation) === "string") {
208 209 switch (data.activation.toLowerCase()) {
209 210 case "singleton":
210 211 opts.activation = ActivationType.Singleton;
211 212 break;
212 213 case "container":
213 214 opts.activation = ActivationType.Container;
214 215 break;
215 216 case "hierarchy":
216 217 opts.activation = ActivationType.Hierarchy;
217 218 break;
218 219 case "context":
219 220 opts.activation = ActivationType.Context;
220 221 break;
221 222 case "call":
222 223 opts.activation = ActivationType.Call;
223 224 break;
224 225 default:
225 226 throw new Error("Unknown activation type: " +
226 227 data.activation);
227 228 }
228 229 } else {
229 230 opts.activation = Number(data.activation);
230 231 }
231 232 }
232 233
233 234 if (data.cleanup)
234 235 opts.cleanup = data.cleanup;
235 236
236 237 return new ServiceDescriptor(opts);
237 238 }
238 239
239 240 _parseObject(data: object, resolver: ModuleResolverBase) {
240 241 if (data.constructor &&
241 242 data.constructor.prototype !== Object.prototype)
242 243 return new ValueDescriptor(data);
243 244
244 245 const o = {};
245 246
246 247 for (const p in data)
247 248 o[p] = this._parse(data[p], resolver);
248 249
249 250 return o;
250 251 }
251 252
252 253 _parseArray(data: Array<any>, resolver: ModuleResolverBase) {
253 254 if (data.constructor &&
254 255 data.constructor.prototype !== Array.prototype)
255 256 return new ValueDescriptor(data);
256 257
257 258 return data.map(x => this._parse(x, resolver));
258 259 }
259 260 }
@@ -1,106 +1,114
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 export interface ReferenceDescriptorParams {
7 name: string;
8 lazy?: boolean;
9 optional?: boolean;
10 default?;
11 services?: ServiceMap;
12 }
13
6 14 export class ReferenceDescriptor implements Descriptor {
7 15 _name: string;
8 16
9 17 _lazy = false;
10 18
11 19 _optional = false;
12 20
13 21 _default: any;
14 22
15 23 _services: ServiceMap;
16 24
17 constructor(name: string, lazy: boolean, optional: boolean, def, services: ServiceMap) {
18 argumentNotEmptyString(name, "name");
19 this._name = name;
20 this._lazy = Boolean(lazy);
21 this._optional = Boolean(optional);
22 this._default = def;
23 this._services = services;
25 constructor(opts: ReferenceDescriptorParams) {
26 argumentNotEmptyString(opts && opts.name, "opts.name");
27 this._name = opts.name;
28 this._lazy = !!opts.lazy;
29 this._optional = !!opts.optional;
30 this._default = !!opts.default;
31 this._services = opts.services;
24 32 }
25 33
26 34 activate(context: ActivationContext, name: string) {
27 35
28 36 if (this._lazy) {
29 37 // сохраняСм контСкст Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ
30 38 context = context.clone();
31 39
32 40 // добавляСм сСрвисы
33 41 if (this._services) {
34 42 for (const p of Object.keys(this._services))
35 43 context.register(p, this._services[p]);
36 44 }
37 45
38 46 return (cfg: ServiceMap) => {
39 47 // Π·Π°Ρ‰ΠΈΡ‰Π°Π΅ΠΌ контСкст Π½Π° случай ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Π² процСссС
40 48 // Π°ΠΊΡ‚ΠΈΠ²Π°Ρ†ΠΈΠΈ
41 49 const ct = context.clone();
42 50 try {
43 51 if (cfg) {
44 52 for (const k in cfg)
45 53 ct.register(k, cfg[k]);
46 54 }
47 55
48 56 return this._optional ? ct.getService(this._name, this._default) : ct
49 57 .getService(this._name);
50 58 } catch (error) {
51 59 throw new ActivationError(this._name, ct.getStack(), error);
52 60 }
53 61 };
54 62 } else {
55 63 context.enter(name, this, !!this._services);
56 64
57 65 // добавляСм сСрвисы
58 66 if (this._services) {
59 67 for (const p of Object.keys(this._services))
60 68 context.register(p, this._services[p]);
61 69 }
62 70
63 71 const v = this._optional ?
64 72 context.getService(this._name, this._default) :
65 73 context.getService(this._name);
66 74
67 75 context.leave();
68 76
69 77 return v;
70 78 }
71 79 }
72 80
73 81 isInstanceCreated() {
74 82 return false;
75 83 }
76 84
77 85 getInstance() {
78 86 throw new Error("The reference descriptor doesn't allowed to hold an instance");
79 87 }
80 88
81 89 toString() {
82 90 const opts = [];
83 91 if (this._optional)
84 92 opts.push("optional");
85 93 if (this._lazy)
86 94 opts.push("lazy");
87 95
88 96 const parts = [
89 97 "@ref "
90 98 ];
91 99 if (opts.length) {
92 100 parts.push("{");
93 101 parts.push(opts.join());
94 102 parts.push("} ");
95 103 }
96 104
97 105 parts.push(this._name);
98 106
99 107 if (!isNull(this._default)) {
100 108 parts.push(" = ");
101 109 parts.push(this._default);
102 110 }
103 111
104 112 return parts.join("");
105 113 }
106 114 }
@@ -1,68 +1,68
1 import { isNull } from "../safe";
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 7 isInstanceCreated(): boolean;
8 8 getInstance();
9 9 }
10 10
11 export function isDescriptor(instance): instance is Descriptor {
12 return (!isNull(instance)) &&
13 ("activate" in instance);
11 export function isDescriptor(x): x is Descriptor {
12 return (!isPrimitive(x)) &&
13 (x.activate instanceof Function);
14 14 }
15 15
16 16 export interface ServiceMap {
17 [s: string]: Descriptor;
17 [s: string]: any;
18 18 }
19 19
20 20 export enum ActivationType {
21 21 Singleton,
22 22 Container,
23 23 Hierarchy,
24 24 Context,
25 25 Call
26 26 }
27 27
28 28 export interface RegistrationWithServices {
29 29 services?: object;
30 30 }
31 31
32 32 export interface ServiceRegistration extends RegistrationWithServices {
33 33 $type?: string | Constructor;
34 34
35 35 $factory?: string | Factory;
36 36
37 37 activation?: "singleton" | "container" | "hierarchy" | "context" | "call";
38 38
39 39 params?;
40 40
41 41 inject?: object | object[];
42 42
43 43 cleanup: (instance) => void | string;
44 44 }
45 45
46 46 export interface ValueRegistration {
47 47 $value;
48 48 parse?: boolean;
49 49 }
50 50
51 51 export interface DependencyRegistration extends RegistrationWithServices {
52 52 $dependency: string;
53 53 lazy?: boolean;
54 54 optional?: boolean;
55 55 default?;
56 56 }
57 57
58 58 export function isServiceRegistration(x): x is ServiceRegistration {
59 return x && ("$type" in x || "$factory" in x);
59 return (!isPrimitive(x)) && ("$type" in x || "$factory" in x);
60 60 }
61 61
62 62 export function isValueRegistration(x): x is ValueRegistration {
63 return x && "$value" in x;
63 return (!isPrimitive(x)) && ("$value" in x);
64 64 }
65 65
66 66 export function isDependencyRegistration(x): x is DependencyRegistration {
67 return x && "$depdendency" in x;
67 return (!isPrimitive(x)) && ("$depdendency" in x);
68 68 }
@@ -1,3 +1,4
1 define(["./ActivatableTests", "./trace-test", "./TraceSourceTests", "./CancellationTests"]);
1 //define(["./ActivatableTests", "./trace-test", "./TraceSourceTests", "./CancellationTests"]);
2 2 //define(["./CancellationTests"]);
3 //define(["./ObservableTests"]); No newline at end of file
3 //define(["./ObservableTests"]);
4 define(["./ContainerTests"]); No newline at end of file
@@ -1,108 +1,60
1 import * as tape from 'tape';
2 import { ActivatableMixin} from '@implab/core/components/ActivatableMixin';
3 import { AsyncComponent } from '@implab/core/components/AsyncComponent';
4 import { IActivationController, IActivatable, ICancellation } from '@implab/core/interfaces';
5 import { Cancellation } from '@implab/core/Cancellation';
6
7 class SimpleActivatable extends ActivatableMixin(AsyncComponent) {
8
9 }
10
11 class MockActivationController implements IActivationController {
12
13 _active: IActivatable = null;
14
15
16 getActive() : IActivatable {
17 return this._active;
18 }
19
20 async deactivate() {
21 if (this._active)
22 await this._active.deactivate();
23 this._active = null;
24 }
1 import * as tape from "tape";
2 import { MockActivationController } from "./mock/MockActivationController";
3 import { SimpleActivatable } from "./mock/SimpleActivatable";
25 4
26 async activate(component: IActivatable) {
27 if (!component || component.isActive())
28 return;
29 component.setActivationController(this);
30
31 await component.activate();
32 }
33
34 async activating(component: IActivatable, ct: ICancellation = Cancellation.none) {
35 if (component != this._active)
36 await this.deactivate();
37 }
5 tape("simple activation", async t => {
38 6
39 async activated(component: IActivatable, ct: ICancellation = Cancellation.none) {
40 this._active = component;
41 }
42
43 async deactivating(component: IActivatable, ct: ICancellation = Cancellation.none) {
44
45 }
46
47 async deactivated(component: IActivatable, ct: ICancellation = Cancellation.none) {
48 if (this._active == component)
49 this._active = null;
50 }
51 }
52
53 tape('simple activation',async function(t){
54
55 let a = new SimpleActivatable();
7 const a = new SimpleActivatable();
56 8 t.false(a.isActive());
57 9
58 10 await a.activate();
59 11 t.true(a.isActive());
60 12
61 13 await a.deactivate();
62 14 t.false(a.isActive());
63 15
64 16 t.end();
65 17 });
66 18
67 tape('controller activation', async function(t) {
19 tape("controller activation", async t => {
68 20
69 let a = new SimpleActivatable();
70 let c = new MockActivationController();
21 const a = new SimpleActivatable();
22 const c = new MockActivationController();
71 23
72 24 t.false(a.isActive(), "the component is not active by default");
73 25 t.assert(c.getActive() == null, "the activation controller doesn't have an active component by default");
74 26 t.assert(a.getActivationController() == null, "the component doesn't have an activation controller by default");
75 27
76 28 t.comment("Active the component through the controller");
77 29 await c.activate(a);
78 30 t.true(a.isActive(), "The component should successfully activate");
79 31 t.equal(c.getActive(), a, "The controller should point to the activated component");
80 32 t.equal(a.getActivationController(), c, "The component should point to the controller");
81 33
82 34 t.comment("Deactive the component throug the controller");
83 35 await c.deactivate();
84 36
85 37 t.false(a.isActive(), "The component should successfully deactivate");
86 38 t.equal(c.getActive(), null, "The controller shouldn't point to any component");
87 39 t.equal(a.getActivationController(), c, "The componet should point to it's controller");
88 40
89 41 t.end();
90 42 });
91 43
92 tape('handle error in onActivating', async function(t) {
93 let a = new SimpleActivatable();
44 tape("handle error in onActivating", async t => {
45 const a = new SimpleActivatable();
94 46
95 a.onActivating = async function() {
96 throw "Should fail";
47 a.onActivating = async () => {
48 throw new Error("Should fail");
97 49 };
98 50
99 51 try {
100 52 await a.activate();
101 53 t.fail("activation should fail");
102 54 } catch {
103 55 }
104 56
105 57 t.false(a.isActive(), "the component should remain inactive");
106 58
107 59 t.end();
108 }); No newline at end of file
60 });
@@ -1,97 +1,97
1 import * as tape from 'tape';
2 import { Cancellation } from '@implab/core/Cancellation';
3 import { ICancellation } from '@implab/core/interfaces';
4 import { delay } from './TestTraits';
1 import * as tape from "tape";
2 import { Cancellation } from "@implab/core/Cancellation";
3 import { ICancellation } from "@implab/core/interfaces";
4 import { delay } from "./TestTraits";
5 5
6 tape('standalone cancellation', async t => {
6 tape("standalone cancellation", async t => {
7 7
8 8 let doCancel: (e) => void;
9 9
10 let ct = new Cancellation(cancel => {
10 const ct = new Cancellation(cancel => {
11 11 doCancel = cancel;
12 12 });
13 13
14 14 let counter = 0;
15 let reason = "BILL";
15 const reason = "BILL";
16 16
17 17 t.true(ct.isSupported(), "Cancellation must be supported");
18 18 t.false(ct.isRequested(), "Cancellation shouldn't be requested");
19 19 ct.throwIfRequested();
20 20 t.pass("The exception shouldn't be thrown unless the cancellation is requested");
21 21
22 22 ct.register(() => counter++);
23 23 t.equals(counter, 0, "counter should be zero");
24 24
25 25 ct.register(() => counter++).destroy();
26 26
27 27 doCancel(reason);
28 28
29 29 t.true(ct.isRequested(), "Cancellation should be requested");
30 30 t.equals(counter, 1, "The registered callback should be triggered");
31 31
32 32 ct.register(() => counter++);
33 33 t.equals(counter, 2, "The callback should be triggered immediately");
34 34
35 35 let msg;
36 ct.register((e) => msg = e);
36 ct.register(e => msg = e);
37 37 t.equals(msg, reason, "The cancellation reason should be passed to callback");
38 38
39 39 try {
40 40 msg = null;
41 41 ct.throwIfRequested();
42 42 t.fail("The exception should be thrown");
43 43 } catch (e) {
44 44 msg = e;
45 45 }
46 46 t.equals(msg, reason, "The cancellation reason should be catched");
47 47
48 48 t.end();
49 49 });
50 50
51 tape('async cancellation', async t => {
51 tape("async cancellation", async t => {
52 52
53 let ct = new Cancellation(cancel => {
53 const ct = new Cancellation(cancel => {
54 54 cancel("STOP!");
55 55 });
56 56
57 57 try {
58 58 await delay(0, ct);
59 59 t.fail("Should thow the exception");
60 60 } catch (e) {
61 61 t.equals(e, "STOP!", "Should throw the cancellation reason");
62 62 }
63 63
64 64 t.end();
65 65 });
66 66
67 tape('cancel with external event', async t => {
68 let ct = new Cancellation((cancel) => {
69 setTimeout(x => cancel('STOP!'), 0);
70 })
67 tape("cancel with external event", async t => {
68 const ct = new Cancellation(cancel => {
69 setTimeout(x => cancel("STOP!"), 0);
70 });
71 71
72 72 try {
73 73 await delay(10000, ct);
74 74 t.fail("Should thow the exception");
75 75 } catch (e) {
76 76 t.equals(e, "STOP!", "Should throw the cancellation reason");
77 77 }
78 78
79 79 t.end();
80 80 });
81 81
82 tape('operation normal flow', async t => {
82 tape("operation normal flow", async t => {
83 83
84 84 let htimeout;
85 let ct = new Cancellation((cancel) => {
85 const ct = new Cancellation(cancel => {
86 86 htimeout = setTimeout(() => cancel("STOP!"), 1000);
87 87 });
88 88
89 89 try {
90 90 await delay(0, ct);
91 91 t.pass("Should pass");
92 92 } finally {
93 93 clearTimeout(htimeout);
94 94 }
95 95
96 96 t.end();
97 }); No newline at end of file
97 });
@@ -1,74 +1,73
1 import { TraceSource, DebugLevel } from '@implab/core/log/TraceSource'
2 import * as tape from 'tape';
3 import { TapeWriter, delay } from './TestTraits';
4 import { Observable } from '@implab/core/Observable';
5 import { IObservable } from '@implab/core/interfaces';
6
7 let trace = TraceSource.get("ObservableTests");
1 import { TraceSource, DebugLevel } from "@implab/core/log/TraceSource";
2 import * as tape from "tape";
3 import { TapeWriter, delay } from "./TestTraits";
4 import { Observable } from "@implab/core/Observable";
5 import { IObservable } from "@implab/core/interfaces";
8 6
9 tape('events sequence example', async t => {
7 const trace = TraceSource.get("ObservableTests");
10 8
9 tape("events sequence example", async t => {
11 10
12 let events: IObservable<number>
11 let events: IObservable<number>;
13 12
14 let done = new Promise<void>((resolve) => {
15 events = new Observable<number>(async (notify, fail, complete) => {
13 const done = new Promise<void>(resolve => {
14 events = new Observable<number>(async (notify, fail, finish) => {
16 15 for (let i = 0; i < 10; i++) {
17 16 await delay(0);
18 17 notify(i);
19 18 }
20 complete();
19 finish();
21 20 resolve();
22 21 });
23 22 });
24 23
25 24 let count = 0;
26 25 let complete = false;
27 26 events.on(x => count = count + x, null, () => complete = true);
28 27
29 let first = await events.next();
28 const first = await events.next();
30 29
31 30 t.equals(first, 0, "the first event");
32 31 t.false(complete, "the sequence is not complete");
33 32
34 33 await done;
35 34
36 35 t.equals(count, 45, "the summ of the evetns");
37 36 t.true(complete, "the sequence is complete");
38 37
39 38 t.end();
40 39 });
41 40
42 tape('event sequence termination', async t => {
43 let events: IObservable<number>
41 tape("event sequence termination", async t => {
42 let events: IObservable<number>;
44 43
45 let done = new Promise<void>((resolve) => {
44 const done = new Promise<void>(resolve => {
46 45 events = new Observable<number>(async (notify, fail, complete) => {
47 46 await delay(0);
48 47 notify(1);
49 48 complete();
50 49 notify(2);
51 50 complete();
52 51 fail("Sequence terminated");
53 52 resolve();
54 53 });
55 54 });
56 55
57 56 let count = 0;
58 events.on(() => {}, (e) => count++, () => count++);
57 events.on(() => {}, e => count++, () => count++);
59 58
60 let first = await events.next();
59 const first = await events.next();
61 60 t.equals(first, 1, "the first message");
62 61 try {
63 62 await events.next();
64 63 t.fail("shoud throw an exception");
65 64 } catch(e) {
66 65 t.pass("the sequence is terminated");
67 66 }
68 67
69 68 await done;
70 69
71 70 t.equals(count, 1, "the sequence must be terminated once");
72 71
73 72 t.end();
74 }); No newline at end of file
73 });
@@ -1,62 +1,75
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 import * as tape from 'tape';
4 import * as tape from "tape";
5 5 import { argumentNotNull } from "@implab/core/safe";
6 6
7 7 export class TapeWriter implements IDestroyable {
8 readonly _tape: tape.Test
8 readonly _tape: tape.Test;
9 9
10 10 _subscriptions = new Array<IDestroyable>();
11 11
12 constructor(tape: tape.Test) {
13 argumentNotNull(tape, "tape");
14 this._tape = tape;
12 constructor(t: tape.Test) {
13 argumentNotNull(t, "tape");
14 this._tape = t;
15 15 }
16 16
17 17 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
18 let subscription = source.on(this.writeEvent.bind(this));
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 let ht = setTimeout(() => {
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 };
62 } No newline at end of file
61 }
62 }
63
64 export function test(name: string, cb: (t: tape.Test) => any) {
65 tape(name, async t => {
66 try {
67 await cb(t);
68 } catch (e) {
69 console.error(e);
70 t.fail(e);
71 } finally {
72 t.end();
73 }
74 });
75 }
@@ -1,69 +1,69
1 import { TraceSource, DebugLevel } from '@implab/core/log/TraceSource'
2 import * as tape from 'tape';
3 import { TapeWriter } from './TestTraits';
1 import { TraceSource, DebugLevel } from "@implab/core/log/TraceSource";
2 import * as tape from "tape";
3 import { TapeWriter } from "./TestTraits";
4 4
5 const sourceId = 'test/TraceSourceTests';
5 const sourceId = "test/TraceSourceTests";
6 6
7 tape('trace message', t => {
8 let trace = TraceSource.get(sourceId);
7 tape("trace message", t => {
8 const trace = TraceSource.get(sourceId);
9 9
10 10 trace.level = DebugLevel;
11 11
12 let h = trace.events.on((ev) => {
12 const h = trace.events.on(ev => {
13 13 t.equal(ev.source, trace, "sender should be the current trace source");
14 14 t.equal(ev.level, DebugLevel, "level should be debug level");
15 15 t.equal(ev.arg, "Hello, World!", "The message should be a formatted message");
16 16
17 17 t.end();
18 18 });
19 19
20 20 trace.debug("Hello, {0}!", "World");
21 21
22 22 h.destroy();
23 23 });
24 24
25 tape('trace event', t => {
26 let trace = TraceSource.get(sourceId);
25 tape("trace event", t => {
26 const trace = TraceSource.get(sourceId);
27 27
28 28 trace.level = DebugLevel;
29 29
30 let event = {
30 const event = {
31 31 name: "custom event"
32 32 };
33 33
34 let h = trace.events.on((ev) => {
34 const h = trace.events.on(ev => {
35 35 t.equal(ev.source, trace, "sender should be the current trace source");
36 36 t.equal(ev.level, DebugLevel, "level should be debug level");
37 37 t.equal(ev.arg, event, "The message should be the specified object");
38 38
39 39 t.end();
40 40 });
41 41
42 42 trace.traceEvent(DebugLevel, event);
43 43
44 44 h.destroy();
45 45 });
46 46
47 tape('tape comment writer', async t => {
48 let writer = new TapeWriter(t);
47 tape("tape comment writer", async t => {
48 const writer = new TapeWriter(t);
49 49
50 50 TraceSource.on(ts => {
51 51 writer.writeEvents(ts.events);
52 52 });
53 53
54 let trace = TraceSource.get(sourceId);
54 const trace = TraceSource.get(sourceId);
55 55 trace.level = DebugLevel;
56 56
57 trace.log("Hello, {0}!", 'World');
57 trace.log("Hello, {0}!", "World");
58 58 trace.log("Multi\n line");
59 59 trace.warn("Look at me!");
60 60 trace.error("DIE!");
61 61
62 62 writer.destroy();
63 63
64 64 trace.log("You shouldn't see it!");
65 65
66 66 t.comment("DONE");
67 67
68 68 t.end();
69 }); No newline at end of file
69 });
General Comments 0
You need to be logged in to leave comments. Login now