##// END OF EJS Templates
Container.configure sync/async tests
cin -
r42:3a5e68edd843 di-typescript
parent child
Show More
@@ -0,0 +1,17
1 define({
2 foo: {
3 $type: "./Foo#Foo"
4 },
5
6 bar: {
7 $type: "./Bar#Bar",
8 params: {
9 db: {
10 provider: {
11 $dependency: "db"
12 }
13 }
14 }
15 },
16 db: "db://localhost"
17 }); No newline at end of file
@@ -1,6 +1,6
1 1 import { TraceSource } from "../log/TraceSource";
2 2 import { argumentNotNull, argumentNotEmptyString, isPrimitive, each, isNull } from "../safe";
3 import { Descriptor, ServiceMap, isDescriptor } from "./interfaces";
3 import { Descriptor, ServiceMap } from "./interfaces";
4 4 import { Container } from "./Container";
5 5
6 6 const trace = TraceSource.get("@implab/core/di/ActivationContext");
@@ -1,14 +1,17
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, DependencyRegistration } from "./interfaces";
4 import { isDescriptor, ActivationType, ServiceMap, isDependencyRegistration, isValueRegistration, ServiceRegistration, DependencyRegistration, ValueRegistration } from "./interfaces";
5 5 import { AggregateDescriptor } from "./AggregateDescriptor";
6 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 import { TraceSource } from "../log/TraceSource";
12 import { RequireJsResolver } from "./RequireJsResolver";
13
14 const trace = TraceSource.get("@implab/core/di/ActivationContext");
12 15
13 16 export class Container {
14 17 _services: ServiceMap;
@@ -30,6 +33,7 export class Container {
30 33 this._cleanup = [];
31 34 this._root = parent ? parent.getRootContainer() : this;
32 35 this._services.container = new ValueDescriptor(this);
36 this._resolver = new RequireJsResolver();
33 37 }
34 38
35 39 getRootContainer() {
@@ -57,6 +61,9 export class Container {
57 61 }
58 62 }
59 63
64 /**
65 * @deprecated use resolve() method
66 */
60 67 getService(name: string, def?) {
61 68 return this.resolve.apply(this, arguments);
62 69 }
@@ -101,10 +108,12 export class Container {
101 108 */
102 109 async configure(config: string | object, opts?: object) {
103 110 if (typeof (config) === "string") {
111 trace.log(`load configuration '${config}'`);
104 112 const resolver = await this._resolver.createResolver(config, opts);
105 113 const data = await this._resolver.loadModule(config);
106 114 return this._configure(data, { resolver });
107 115 } else {
116 trace.log(`json configuration`);
108 117 return this._configure(config);
109 118 }
110 119 }
@@ -133,27 +142,30 export class Container {
133 142 this.register(services);
134 143 }
135 144
136 async _parse(registration: any, resolver: ModuleResolverBase) {
137 if (isPrimitive(registration) || isDescriptor(registration))
138 return registration;
145 async _parse(data: any, resolver: ModuleResolverBase) {
146 if (isPrimitive(data) || isDescriptor(data))
147 return data;
139 148
140 if (isDependencyRegistration(registration)) {
141 return this._paseReference(registration, resolver);
142 } else if (isValueRegistration(registration)) {
143 return !registration.parse ?
144 new ValueDescriptor(registration.$value) :
145 new AggregateDescriptor(this._parse(registration.$value, resolver));
146
147 } else if (registration.$type || registration.$factory) {
148 return this._parseService(registration, resolver);
149 } else if (registration instanceof Array) {
150 return this._parseArray(registration, resolver);
149 if (isDependencyRegistration(data)) {
150 return this._makeReferenceDescriptor(data, resolver);
151 } else if (isValueRegistration(data)) {
152 return this._makeValueDescriptor(data, resolver);
153 } else if (data.$type || data.$factory) {
154 return this._makeServiceDescriptor(data, resolver);
155 } else if (data instanceof Array) {
156 return this._parseArray(data, resolver);
151 157 }
152 158
153 return this._parseObject(registration, resolver);
159 return this._parseObject(data, resolver);
154 160 }
155 161
156 async _paseReference(registration: DependencyRegistration, resolver: ModuleResolverBase) {
162 async _makeValueDescriptor(data: ValueRegistration, resolver: ModuleResolverBase) {
163 return !data.parse ?
164 new ValueDescriptor(data.$value) :
165 new AggregateDescriptor(this._parse(data.$value, resolver));
166 }
167
168 async _makeReferenceDescriptor(registration: DependencyRegistration, resolver: ModuleResolverBase) {
157 169 return new ReferenceDescriptor({
158 170 name: registration.$dependency,
159 171 lazy: registration.lazy,
@@ -163,7 +175,7 export class Container {
163 175 });
164 176 }
165 177
166 async _parseService(data: ServiceRegistration, resolver: ModuleResolverBase) {
178 async _makeServiceDescriptor(data: ServiceRegistration, resolver: ModuleResolverBase) {
167 179 const opts: ServiceDescriptorParams = {
168 180 owner: this
169 181 };
@@ -195,7 +207,7 export class Container {
195 207 }
196 208
197 209 if (data.params)
198 opts.params = this._parse(data.params, resolver);
210 opts.params = await this._parse(data.params, resolver);
199 211
200 212 if (data.activation) {
201 213 if (typeof (data.activation) === "string") {
@@ -3,9 +3,12 import { Uuid } from "../Uuid";
3 3 import { argumentNotEmptyString } from "../safe";
4 4 import { TraceSource } from "../log/TraceSource";
5 5
6 declare function require(modules: string[], cb?: (...args: any[]) => any): void;
6 type RequireFn = (modules: string[], cb?: (...args: any[]) => any) => void;
7 7
8 declare function define(name: string, modules: string[], cb?: (...args: any[]) => any): void;
8 declare const require: RequireFn;
9
10 declare function define(name: string, modules: string[], cb?: (...args: any[]) => any, eb?: (e) => any): void;
11 declare function define(modules: string[], cb?: (...args: any[]) => any, eb?: (e) => any): void;
9 12
10 13 interface RequireJsResolverParams {
11 14 contextRequire: (modules: string[], cb?: (...args: any[]) => any) => void;
@@ -13,14 +16,14 interface RequireJsResolverParams {
13 16 base: string;
14 17 }
15 18
16 TraceSource.get("RequireJsResolver");
19 const trace = TraceSource.get("@implab/core/di/RequireJsResolver");
17 20
18 21 export class RequireJsResolver extends ModuleResolverBase {
19 22 _contextRequire = require;
20 23
21 24 _base: string;
22 25
23 constructor(opts) {
26 constructor(opts?: RequireJsResolverParams) {
24 27 super();
25 28
26 29 if (opts) {
@@ -40,6 +43,8 export class RequireJsResolver extends M
40 43 async createResolver(moduleName: string): Promise<ModuleResolverBase> {
41 44 argumentNotEmptyString(moduleName, "moduleName");
42 45
46 trace.log("createResolver({0})", moduleName);
47
43 48 const parts = moduleName.split("/");
44 49 if (parts[0] === ".") {
45 50 if (this._base)
@@ -55,17 +60,38 export class RequireJsResolver extends M
55 60
56 61 const shim = parts.join("/");
57 62
58 const contextRequire = await new Promise(
59 resolve => define(shim, ["require"], resolve)
60 );
63 trace.debug(`define shim ${shim}`);
61 64
62 return new RequireJsResolver({
63 base: parts.slice(0, -1).join("/"),
64 contextRequire
65 });
65 try {
66 const contextRequire = await new Promise<RequireFn>(
67 (resolve, reject) => {
68 try {
69 define(shim, ["require"], r => {
70 trace.debug("shim resolved");
71 resolve(r);
72 }, reject);
73 require([shim]);
74 } catch (e) {
75 reject(e);
76 }
77 }
78 );
79
80 trace.debug("creating new moduleResolver");
81
82 return new RequireJsResolver({
83 base: parts.slice(0, -1).join("/"),
84 contextRequire
85 });
86 } catch (e) {
87 trace.error(e);
88 throw e;
89 }
90
66 91 }
67 92
68 93 async loadModule(moduleName: string): Promise<object> {
94 trace.log(`loadModule(${moduleName})`);
69 95 return new Promise<object>(
70 96 resolve => this._contextRequire.call(null, [moduleName], resolve)
71 97 );
@@ -37,17 +37,19 function _parse(value, context: Activati
37 37 if (isPrimitive(value))
38 38 return value;
39 39
40 trace.debug("parse {0}", path);
41
40 42 if (isDescriptor(value))
41 43 return context.activate(value, path);
42 44
43 45 if (value instanceof Array)
44 return value.map((x, i) => this._parse(x, context, `${path}[${i}]`));
46 return value.map((x, i) => _parse(x, context, `${path}[${i}]`));
45 47
46 48 const t = {};
47 49 for (const p of Object.keys(value))
48 t[p] = this._parse(value[p], context, `${path}.${p}`);
50 t[p] = _parse(value[p], context, `${path}.${p}`);
51
49 52 return t;
50
51 53 }
52 54
53 55 export interface ServiceDescriptorParams {
@@ -62,5 +62,5 export function isValueRegistration(x):
62 62 }
63 63
64 64 export function isDependencyRegistration(x): x is DependencyRegistration {
65 return (!isPrimitive(x)) && ("$depdendency" in x);
65 return (!isPrimitive(x)) && ("$dependency" in x);
66 66 }
@@ -1,7 +1,7
1 import * as format from '../text/format'
2 import { argumentNotNull } from '../safe';
3 import { Observable } from '../Observable'
4 import { IDestroyable } from '../interfaces';
1 import * as format from "../text/format";
2 import { argumentNotNull } from "../safe";
3 import { Observable } from "../Observable";
4 import { IDestroyable } from "../interfaces";
5 5
6 6 export const DebugLevel = 400;
7 7
@@ -16,11 +16,11 export const SilentLevel = 0;
16 16 export class TraceEvent {
17 17 readonly source: TraceSource;
18 18
19 readonly level: Number;
19 readonly level: number;
20 20
21 21 readonly arg: any;
22 22
23 constructor(source: TraceSource, level: Number, arg: any) {
23 constructor(source: TraceSource, level: number, arg: any) {
24 24 this.source = source;
25 25 this.level = level;
26 26 this.arg = arg;
@@ -185,4 +185,3 export class TraceSource {
185 185 return Registry.instance.get(id);
186 186 }
187 187 }
188
@@ -20,20 +20,31 test("Container register/resolve tests",
20 20
21 21 const connection1 = "db://localhost";
22 22
23 container.register("connection", new ValueDescriptor(connection1));
23 t.throws(
24 () => container.register("bla-bla", "bla-bla"),
25 "Do not allow to register anything other than descriptors"
26 );
24 27
25 t.equals(container.getService("connection"), connection1);
28 t.doesNotThrow(
29 () => container.register("connection", new ValueDescriptor(connection1)),
30 "register ValueDescriptor"
31 );
26 32
27 container.register(
28 "dbParams",
29 new AggregateDescriptor({
30 timeout: 10,
31 connection: new ReferenceDescriptor({ name: "connection" })
32 })
33 t.equals(container.getService("connection"), connection1, "resolve string value");
34
35 t.doesNotThrow(
36 () => container.register(
37 "dbParams",
38 new AggregateDescriptor({
39 timeout: 10,
40 connection: new ReferenceDescriptor({ name: "connection" })
41 })
42 ),
43 "register AggregateDescriptor"
33 44 );
34 45
35 46 const dbParams = container.getService("dbParams");
36 t.equals(dbParams.connection, connection1, "should get connection");
47 t.equals(dbParams.connection, connection1, "should get string value 'dbParams.connection'");
37 48
38 49 writer.destroy();
39 50 });
@@ -53,6 +64,13 test("Container configure/resolve tests"
53 64 $type: Foo
54 65 },
55 66
67 box: {
68 $type: Bar,
69 params: {
70 $dependency: "foo"
71 }
72 },
73
56 74 bar: {
57 75 $type: Bar,
58 76 params: {
@@ -64,11 +82,37 test("Container configure/resolve tests"
64 82 }
65 83 }
66 84 });
85 t.pass("should configure from js object");
67 86
68 87 const f1 = container.resolve("foo");
88
89 t.assert(!isNull(f1), "foo should be not null");
90
91 t.throws(() => container.resolve("bar"), "should not resolve dependency 'db'");
92
93 writer.destroy();
94 });
95
96 test("Load configuration from module", async t => {
97 const writer = new TapeWriter(t);
98
99 TraceSource.on(ts => {
100 ts.level = DebugLevel;
101 writer.writeEvents(ts.events);
102 });
103
104 const container = new Container();
105
106 await container.configure("test/mock/config1");
107 t.pass("The configuration should load");
108
109 const f1 = container.resolve("foo");
110
69 111 t.assert(!isNull(f1), "foo should be not null");
70 112
71 113 const b1 = container.resolve("bar");
72 114
115 t.assert(!isNull(b1), "foo should be not null");
116
73 117 writer.destroy();
74 118 });
General Comments 0
You need to be logged in to leave comments. Login now